diff options
194 files changed, 6560 insertions, 3793 deletions
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 88facc8..517c74e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -38,7 +38,7 @@ jobs: test-macos: name: Test Spike build (MacOS) - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v2 with: @@ -7,3 +7,4 @@ autom4te.cache/ .gdb_history .#* *~ +config.log diff --git a/Makefile.in b/Makefile.in index f90159e..66d087b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,7 +93,7 @@ VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled)) # These all appear on the command line, from lowest precedence to # highest. -default-CFLAGS := -DPREFIX=\"$(prefix)\" -Wall -Wno-unused -Wno-nonportable-include-path -g -O2 -fPIC +default-CFLAGS := -DPREFIX=\"$(prefix)\" -Wall -Wno-nonportable-include-path -g -O2 -fPIC default-CXXFLAGS := $(default-CFLAGS) -std=c++2a mcppbs-CPPFLAGS := @CPPFLAGS@ @@ -385,6 +385,15 @@ install-hdrs : $(install_hdrs) $(INSTALL_HDR) $(src_dir)/$$file $(install_hdrs_dir)/`dirname $$file`; \ done +install-hdrs-list.h: $(install_hdrs) + rm -f $@.tmp + for file in $(subst $(src_dir)/,,$^); \ + do \ + $(MKINSTALLDIRS) $(install_hdrs_dir)/`dirname $$file`; \ + echo "#include <$(src_dir)/$$file>" >> $@.tmp; \ + done + mv $@.tmp $@ + install-libs : $(install_libs) $(MKINSTALLDIRS) $(install_libs_dir) for file in $^; \ @@ -13,8 +13,10 @@ Spike supports the following RISC-V ISA features: - RV32E and RV64E base ISAs, v1.9 - Zifencei extension, v2.0 - Zicsr extension, v2.0 + - Zicntr extension, v2.0 - M extension, v2.0 - A extension, v2.1 + - B extension, v1.0 - F extension, v2.2 - D extension, v2.2 - Q extension, v2.2 @@ -28,6 +30,7 @@ Spike supports the following RISC-V ISA features: - Zbc extension, v1.0 - Zbs extension, v1.0 - Zfh and Zfhmin half-precision floating-point extensions, v1.0 + - Zfa extension, v1.0 - Zfinx extension, v1.0 - Zmmul integer multiplication extension, v1.0 - Zicbom, Zicbop, Zicboz cache-block maintenance extensions, v1.0 @@ -37,11 +40,23 @@ Spike supports the following RISC-V ISA features: - Svnapot extension, v1.0 - Svpbmt extension, v1.0 - Svinval extension, v1.0 + - Svadu extension, v1.0 + - Svade extension, v1.0 - Sdext extension, v1.0-STABLE - Sdtrig extension, v1.0-STABLE - Smepmp extension v1.0 - Smstateen extension, v1.0 + - Smdbltrp extension, v1.0 - Sscofpmf v0.5.2 + - Ssdbltrp extension, v1.0 + - Ssqosid extension, v1.0 + - Zaamo extension, v1.0 + - Zalrsc extension, v1.0 + - Zabha extension, v1.0 + - Zacas extension, v1.0 + - Zawrs extension, v1.0 + - Zicfiss extension, v1.0 + - Zicfilp extension, v1.0 - Zca extension, v1.0 - Zcb extension, v1.0 - Zcf extension, v1.0 @@ -61,8 +76,10 @@ Spike supports the following RISC-V ISA features: - Zvkt extension, v1.0 - Zvkn, Zvknc, Zvkng extension, v1.0 - Zvks, Zvksc, Zvksg extension, v1.0 - - Zilsd extension, v0.9.0 - - Zcmlsd extension, v0.9.0 + - Zicond extension, v1.0 + - Zilsd extension, v1.0 + - Zclsd extension, v1.0 + - Zimop extension, v1.0 Versioning and APIs ------------------- diff --git a/ci-tests/atomics.c b/ci-tests/atomics.c new file mode 100644 index 0000000..ece5a38 --- /dev/null +++ b/ci-tests/atomics.c @@ -0,0 +1,20 @@ +#include <stdio.h> +#include <stdatomic.h> + +atomic_int acnt = 0; +atomic_int bcnt = 0; + +int foo() { + for(int n = 0; n < 1000; ++n) { + ++acnt; + if(acnt % 10 == 0) + ++bcnt; + } + return acnt; +} + +int main(void) { + int acnt = foo(); + printf("First atomic counter is %u, second is %u\n", acnt, bcnt); + return 0; +} diff --git a/ci-tests/build-spike b/ci-tests/build-spike index 058defd..0a1b315 100755 --- a/ci-tests/build-spike +++ b/ci-tests/build-spike @@ -8,10 +8,10 @@ rm -rf build mkdir build cd build mkdir install -CXXFLAGS="-Wnon-virtual-dtor" CFLAGS="-Werror -Wignored-qualifiers -Wunused-function -Wunused-parameter -Wunused-variable" $DIR/../configure --prefix=`pwd`/install +CXXFLAGS="-Wnon-virtual-dtor" CFLAGS="-Werror -Wall -Wextra -Wvla" $DIR/../configure --prefix=`pwd`/install make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" make check -make install +make install install-hdrs-list.h # check that help message prints without error install/bin/spike -h diff --git a/ci-tests/create-ci-binary-tarball b/ci-tests/create-ci-binary-tarball index abc9ee0..1080d0a 100755 --- a/ci-tests/create-ci-binary-tarball +++ b/ci-tests/create-ci-binary-tarball @@ -4,7 +4,7 @@ set -e rm -rf build mkdir -p build/pk && cd "$_" -`git rev-parse --show-toplevel`/../riscv-pk/configure --host=riscv64-unknown-elf +`git rev-parse --show-toplevel`/../riscv-pk/configure --host=riscv64-unknown-elf --with-arch=rv64gc_zifencei make -j4 cd - @@ -16,9 +16,20 @@ mkdir -p build/dummy-slliuw && cd "$_" riscv64-unknown-elf-gcc -O2 -o dummy-slliuw `git rev-parse --show-toplevel`/ci-tests/dummy-slliuw.c cd - +mkdir -p build/dummycsr && cd "$_" +riscv64-unknown-elf-gcc -O2 -o customcsr `git rev-parse --show-toplevel`/ci-tests/customcsr.c +cd - + +mkdir -p build/atomics && cd "$_" +riscv64-unknown-elf-gcc -O2 -o atomics `git rev-parse --show-toplevel`/ci-tests/atomics.c +cd - + + mv build/pk/pk . mv build/hello/hello . mv build/dummy-slliuw/dummy-slliuw . -tar -cf spike-ci.tar pk hello dummy-slliuw +mv build/dummycsr/customcsr . +mv build/atomics/atomics . +tar -cf spike-ci.tar pk hello dummy-slliuw customcsr atomics -rm pk hello dummy-slliuw +rm pk hello dummy-slliuw customcsr atomics diff --git a/ci-tests/custom-csr.cc b/ci-tests/custom-csr.cc new file mode 100644 index 0000000..857c9c3 --- /dev/null +++ b/ci-tests/custom-csr.cc @@ -0,0 +1,82 @@ +#include <riscv/extension.h> +#include <riscv/sim.h> + + +class dummycsr_t: public csr_t { + public: + dummycsr_t(processor_t *proc, const reg_t addr): csr_t(proc, addr) {} + + reg_t read() const noexcept override { + return 42; + } + + void verify_permissions(insn_t insn, bool write) const override {} + + protected: + bool unlogged_write(const reg_t val) noexcept override { + return true; + } +}; + +// dummy extension with dummy CSRs. Nice. +struct xdummycsr_t : public extension_t { + const char *name() const override { return "dummycsr"; } + + xdummycsr_t() {} + + std::vector<insn_desc_t> get_instructions(const processor_t &) override { + return {}; + } + + std::vector<disasm_insn_t *> get_disasms(const processor_t *) override { + return {}; + } + + std::vector<csr_t_p> get_csrs(processor_t &proc) const override { + return {std::make_shared<dummycsr_t>(&proc, /*Addr*/ 0xfff)}; + } +}; + +REGISTER_EXTENSION(dummycsr, []() { return new xdummycsr_t; }) + +// Copied from spike main. +// TODO: This should really be provided in libriscv +static std::vector<std::pair<reg_t, abstract_mem_t *>> +make_mems(const std::vector<mem_cfg_t> &layout) { + std::vector<std::pair<reg_t, abstract_mem_t *>> mems; + mems.reserve(layout.size()); + for (const auto &cfg : layout) { + mems.push_back(std::make_pair(cfg.get_base(), new mem_t(cfg.get_size()))); + } + return mems; +} + +int main(int argc, char **argv) { + cfg_t cfg; + cfg.isa = "RV64IMAFDCV_Zicsr_xdummycsr"; + std::vector<device_factory_sargs_t> plugin_devices; + if (argc != 3) { + std::cerr << "Error: invalid arguments\n"; + exit(1); + } + std::vector<std::string> htif_args{argv[1] /* pk */, argv[2] /* executable */}; + debug_module_config_t dm_config = {.progbufsize = 2, + .max_sba_data_width = 0, + .require_authentication = false, + .abstract_rti = 0, + .support_hasel = true, + .support_abstract_csr_access = true, + .support_abstract_fpr_access = true, + .support_haltgroups = true, + .support_impebreak = true}; + std::vector<std::pair<reg_t, abstract_mem_t *>> mems = + make_mems(cfg.mem_layout); + sim_t sim(&cfg, false, mems, plugin_devices, htif_args, dm_config, + nullptr, // log_path + true, // dtb_enabled + nullptr, // dtb_file + false, // socket_enabled + nullptr, // cmd_file + std::nullopt); // instruction_limit + sim.run(); +} diff --git a/ci-tests/customcsr.c b/ci-tests/customcsr.c new file mode 100644 index 0000000..7d02689 --- /dev/null +++ b/ci-tests/customcsr.c @@ -0,0 +1,12 @@ +#include <stdio.h> + +int main() { + int x = 1; + // dummycsr + asm("csrr %0, 0xfff" : "=r"(x)); + if (x == 42) + printf("Executed successfully\n"); + else + printf("FAIL. Got value: %d instead of 42\n", x); + return 0; +} diff --git a/ci-tests/test-customext.cc b/ci-tests/test-customext.cc index e493811..77c739f 100644 --- a/ci-tests/test-customext.cc +++ b/ci-tests/test-customext.cc @@ -26,11 +26,11 @@ static reg_t do_nop4([[maybe_unused]] processor_t *p, // dummy extension that uses the same prefix as standard zba extension struct xslliuw_dummy_t : public extension_t { - const char *name() { return "dummyslliuw"; } + const char *name() const { return "dummyslliuw"; } xslliuw_dummy_t() {} - std::vector<insn_desc_t> get_instructions() { + std::vector<insn_desc_t> get_instructions(const processor_t &) { std::vector<insn_desc_t> insns; insns.push_back(insn_desc_t{MATCH_SLLI_UW, MASK_SLLI_UW, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, @@ -38,7 +38,7 @@ struct xslliuw_dummy_t : public extension_t { return insns; } - std::vector<disasm_insn_t *> get_disasms() { + std::vector<disasm_insn_t *> get_disasms(const processor_t *) { std::vector<disasm_insn_t *> insns; insns.push_back(new disasm_insn_t("dummy_slliuw", MATCH_SLLI_UW, MASK_SLLI_UW, {&xrd, &xrs1, &shamt})); @@ -85,6 +85,7 @@ int main(int argc, char **argv) { true, // dtb_enabled nullptr, // dtb_file false, // socket_enabled - nullptr); // cmd_file + nullptr, // cmd_file + std::nullopt); // instruction_limit sim.run(); } diff --git a/ci-tests/test-spike b/ci-tests/test-spike index 0540739..6fe5bdb 100755 --- a/ci-tests/test-spike +++ b/ci-tests/test-spike @@ -11,10 +11,16 @@ cd run wget https://github.com/riscv-software-src/riscv-isa-sim/releases/download/dummy-tag-for-ci-storage/spike-ci.tar tar xf spike-ci.tar time ../install/bin/spike --isa=rv64gc pk hello | grep "Hello, world! Pi is approximately 3.141588." +../install/bin/spike --log-commits --isa=rv64gc pk atomics | grep "First atomic counter is 1000, second is 100" # check that including sim.h in an external project works -g++ -std=c++17 -I../install/include -L../install/lib $DIR/testlib.c -lriscv -o test-libriscv -g++ -std=c++17 -I../install/include -L../install/lib $DIR/test-customext.cc -lriscv -o test-customext +g++ -std=c++2a -I../install/include -L../install/lib $DIR/testlib.cc -lriscv -o test-libriscv +g++ -std=c++2a -I../install/include -L../install/lib $DIR/test-customext.cc -lriscv -o test-customext +g++ -std=c++2a -I../install/include -L../install/lib $DIR/custom-csr.cc -lriscv -o test-custom-csr + +# check that all installed headers are functional +g++ -std=c++2a -I../install/include -L../install/lib $DIR/testlib.cc -lriscv -o /dev/null -include ../install-hdrs-list.h LD_LIBRARY_PATH=../install/lib ./test-libriscv pk hello| grep "Hello, world! Pi is approximately 3.141588." LD_LIBRARY_PATH=../install/lib ./test-customext pk dummy-slliuw | grep "Executed successfully" +LD_LIBRARY_PATH=../install/lib ./test-custom-csr pk customcsr | grep "Executed successfully" diff --git a/ci-tests/testlib.c b/ci-tests/testlib.cc index 6bc0886..eb91d97 100644 --- a/ci-tests/testlib.c +++ b/ci-tests/testlib.cc @@ -34,6 +34,7 @@ int main(int argc, char **argv) { true, nullptr, false, - nullptr); + nullptr, + std::nullopt); sim.run(); } diff --git a/config.h.in b/config.h.in index aef3596..e1f8734 100644 --- a/config.h.in +++ b/config.h.in @@ -6,12 +6,6 @@ /* Define if subproject MCPPBS_SPROJ_NORM is enabled */ #undef CUSTOMEXT_ENABLED -/* Default value for --isa switch */ -#undef DEFAULT_ISA - -/* Default value for --priv switch */ -#undef DEFAULT_PRIV - /* Define if subproject MCPPBS_SPROJ_NORM is enabled */ #undef DISASM_ENABLED @@ -42,18 +36,15 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `boost_regex' library (-lboost_regex). */ +/* Define to 1 if you have the 'boost_regex' library (-lboost_regex). */ #undef HAVE_LIBBOOST_REGEX -/* Define to 1 if you have the `boost_system' library (-lboost_system). */ +/* Define to 1 if you have the 'boost_system' library (-lboost_system). */ #undef HAVE_LIBBOOST_SYSTEM -/* Define to 1 if you have the `pthread' library (-lpthread). */ +/* Define to 1 if you have the 'pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H - /* Define to 1 if struct statx exists. */ #undef HAVE_STATX @@ -63,6 +54,9 @@ /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -114,7 +108,9 @@ /* Define if subproject MCPPBS_SPROJ_NORM is enabled */ #undef SPIKE_MAIN_ENABLED -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Default value for --target switch */ @@ -1,11 +1,11 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for RISC-V ISA Simulator ?. +# Generated by GNU Autoconf 2.72 for RISC-V ISA Simulator ?. # # Report bugs to <Andrew Waterman>. # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # @@ -17,7 +17,6 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -26,12 +25,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -103,7 +103,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -133,15 +133,14 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: @@ -149,12 +148,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi " @@ -172,8 +172,9 @@ as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else \$as_nop - exitcode=1; echo positional parameters were not saved. +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -182,19 +183,19 @@ test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else $as_nop - as_have_required=no +else case e in #( + e) as_have_required=no ;; +esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -227,12 +228,13 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi +fi ;; +esac fi @@ -254,7 +256,7 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi @@ -274,7 +276,8 @@ $0: manually run the script under such a shell if you do $0: have one." fi exit 1 -fi +fi ;; +esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -313,14 +316,6 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -389,11 +384,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -407,21 +403,14 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -495,6 +484,8 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits /[$]LINENO/= ' <$as_myself | sed ' + t clear + :clear s/[$]LINENO.*/&-/ t lineno b @@ -543,7 +534,6 @@ esac as_echo='printf %s\n' as_echo_n='printf %s' - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -555,9 +545,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -582,10 +572,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 </dev/null @@ -660,8 +652,6 @@ BOOST_LDFLAGS BOOST_CPPFLAGS HAVE_CLANG_PCH HAVE_INT128 -EGREP -GREP INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM @@ -737,8 +727,6 @@ with_boost with_boost_libdir with_boost_asio with_boost_regex -with_isa -with_priv with_target enable_dual_endian ' @@ -863,7 +851,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -889,7 +877,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1102,7 +1090,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1118,7 +1106,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1148,8 +1136,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" ;; *=*) @@ -1157,7 +1145,7 @@ Try \`$0 --help' for more information" # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1207,7 +1195,7 @@ do as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: `$host' +# There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -1275,7 +1263,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1303,7 +1291,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures RISC-V ISA Simulator ? to adapt to many kinds of systems. +'configure' configures RISC-V ISA Simulator ? to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1317,11 +1305,11 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' + -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] + --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -1329,10 +1317,10 @@ Installation directories: --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. +By default, 'make install' will install all the files in +'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify +an installation prefix other than '$ac_default_prefix' using '--prefix', +for instance '--prefix=\$HOME'. For better control, use the options below. @@ -1403,9 +1391,6 @@ Optional Packages: use the Regex library from boost - it is possible to specify a certain library for the linker e.g. --with-boost-regex=boost_regex-gcc-mt-d-1_33_1 - --with-isa=RV64IMAFDC_zicntr_zihpm - Sets the default RISC-V ISA - --with-priv=MSU Sets the default RISC-V privilege modes supported --with-target=riscv64-unknown-elf Sets the default target config @@ -1422,7 +1407,7 @@ Some influential environment variables: STOW_ROOT Root for non-native stow-based installs STOW_PREFIX Prefix for stow-based installs -Use these variables to override the choices made by `configure' or to help +Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to <Andrew Waterman>. @@ -1490,9 +1475,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF RISC-V ISA Simulator configure ? -generated by GNU Autoconf 2.71 +generated by GNU Autoconf 2.72 -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1531,11 +1516,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1570,17 +1556,66 @@ printf "%s\n" "$ac_try_echo"; } >&5 } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + } +then : + ac_retval=0 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 ;; +esac +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + # ac_fn_cxx_try_run LINENO # ------------------------ # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that @@ -1611,12 +1646,13 @@ printf "%s\n" "$ac_try_echo"; } >&5 test $ac_status = 0; }; } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: program exited with status $ac_status" >&5 +else case e in #( + e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=$ac_status + ac_retval=$ac_status ;; +esac fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1636,8 +1672,8 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -1645,10 +1681,12 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1669,8 +1707,8 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 @@ -1700,12 +1738,14 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - eval "$3=yes" +else case e in #( + e) eval "$3=yes" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1714,53 +1754,6 @@ printf "%s\n" "$ac_res" >&6; } } # ac_fn_cxx_check_type -# ac_fn_cxx_try_link LINENO -# ------------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_link - # ac_fn_cxx_check_member LINENO AGGR MEMBER VAR INCLUDES # ------------------------------------------------------ # Tries to find if the field MEMBER exists in type AGGR, after including @@ -1773,8 +1766,8 @@ printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -1790,8 +1783,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval "$4=yes" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -1807,12 +1800,15 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval "$4=yes" -else $as_nop - eval "$4=no" +else case e in #( + e) eval "$4=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1845,7 +1841,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by RISC-V ISA Simulator $as_me ?, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -2091,10 +2087,10 @@ esac printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi done @@ -2130,9 +2126,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -2146,6 +2140,21 @@ static char *f (char * (*g) (char **, int), char **p, ...) return s; } +/* C89 style stringification. */ +#define noexpand_stringify(a) #a +const char *stringified = noexpand_stringify(arbitrary+token=sequence); + +/* C89 style token pasting. Exercises some of the corner cases that + e.g. old MSVC gets wrong, but not very hard. */ +#define noexpand_concat(a,b) a##b +#define expand_concat(a,b) noexpand_concat(a,b) +extern int vA; +extern int vbee; +#define aye A +#define bee B +int *pvA = &expand_concat(v,aye); +int *pvbee = &noexpand_concat(v,bee); + /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated @@ -2173,16 +2182,19 @@ ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? +/* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif +// See if C++-style comments work. + #include <stdbool.h> extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); +extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare @@ -2232,7 +2244,6 @@ typedef const char *ccp; static inline int test_restrict (ccp restrict text) { - // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) @@ -2298,6 +2309,8 @@ ac_c_conftest_c99_main=' ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; + // Work around memory leak warnings. + free (ia); // Check named initializers. struct named_init ni = { @@ -2319,7 +2332,7 @@ ac_c_conftest_c99_main=' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? +/* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif @@ -2727,8 +2740,9 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; +esac fi @@ -2756,12 +2770,12 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -2770,18 +2784,18 @@ printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. @@ -2797,11 +2811,11 @@ printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## @@ -2835,15 +2849,16 @@ printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_build_alias=$build_alias +else case e in #( + e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } @@ -2870,14 +2885,15 @@ printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "x$host_alias" = x; then +else case e in #( + e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } @@ -3004,7 +3020,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 6 +#serial 11 # =========================================================================== @@ -3096,10 +3112,10 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # # Test for the Boost C++ libraries of a particular version (or newer) # -# If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt and /opt/local and evaluates the -# $BOOST_ROOT environment variable. Further documentation is available at -# <http://randspringer.de/boost/index.html>. +# If no path to the installed boost library is given the macro searches +# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates +# the $BOOST_ROOT environment variable. Further documentation is available +# at <http://randspringer.de/boost/index.html>. # # This macro calls: # @@ -3119,7 +3135,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 49 +#serial 55 # example boost program (need to pass version) @@ -3231,8 +3247,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3254,7 +3270,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3276,8 +3293,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3299,7 +3316,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3334,8 +3352,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3357,7 +3375,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3379,8 +3398,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -3419,7 +3438,8 @@ if test $ac_prog_rejected = yes; then ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3443,8 +3463,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3466,7 +3486,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3492,8 +3513,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3515,7 +3536,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3553,8 +3575,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3576,7 +3598,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3598,8 +3621,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3621,7 +3644,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3650,10 +3674,10 @@ fi fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3725,8 +3749,8 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. +# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -3746,7 +3770,7 @@ do ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' + # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -3757,8 +3781,9 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else $as_nop - ac_file='' +else case e in #( + e) ac_file='' ;; +esac fi if test -z "$ac_file" then : @@ -3767,13 +3792,14 @@ printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } @@ -3797,10 +3823,10 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. + # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) +# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will +# work properly (i.e., refer to 'conftest.exe'), while it won't with +# 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -3810,11 +3836,12 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3830,6 +3857,8 @@ int main (void) { FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; return ferror (f) || fclose (f) != 0; ; @@ -3869,26 +3898,27 @@ printf "%s\n" "$ac_try_echo"; } >&5 if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -3920,16 +3950,18 @@ then : break;; esac done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } @@ -3940,8 +3972,8 @@ printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -3958,12 +3990,14 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -3981,8 +4015,8 @@ printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -4000,8 +4034,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" +else case e in #( + e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4016,8 +4050,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4034,12 +4068,15 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -4066,8 +4103,8 @@ printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no +else case e in #( + e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4084,25 +4121,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" + CC="$CC $ac_cv_prog_cc_c11" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 + ac_prog_cc_stdc=c11 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -4112,8 +4152,8 @@ printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no +else case e in #( + e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4130,25 +4170,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" + CC="$CC $ac_cv_prog_cc_c99" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 + ac_prog_cc_stdc=c99 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -4158,8 +4201,8 @@ printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no +else case e in #( + e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4176,25 +4219,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" + CC="$CC $ac_cv_prog_cc_c89" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 + ac_prog_cc_stdc=c89 ;; +esac fi fi @@ -4229,8 +4275,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then +else case e in #( + e) if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4252,7 +4298,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then @@ -4278,8 +4325,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then +else case e in #( + e) if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4301,7 +4348,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then @@ -4361,8 +4409,8 @@ printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -4379,12 +4427,14 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } @@ -4402,8 +4452,8 @@ printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag +else case e in #( + e) ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" @@ -4421,8 +4471,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" +else case e in #( + e) CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4437,8 +4487,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag +else case e in #( + e) ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4455,12 +4505,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag + ac_cxx_werror_flag=$ac_save_cxx_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } @@ -4484,11 +4537,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_11=no +else case e in #( + e) ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4505,36 +4558,39 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" + CXX="$CXX $ac_cv_prog_cxx_cxx11" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 + ac_prog_cxx_stdcxx=cxx11 ;; +esac fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_98=no +else case e in #( + e) ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4551,25 +4607,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" + CXX="$CXX $ac_cv_prog_cxx_cxx98" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 + ac_prog_cxx_stdcxx=cxx98 ;; +esac fi fi @@ -4587,8 +4646,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AR"; then +else case e in #( + e) if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4610,7 +4669,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi AR=$ac_cv_prog_AR if test -n "$AR"; then @@ -4632,8 +4692,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_AR"; then +else case e in #( + e) if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4655,7 +4715,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then @@ -4689,8 +4750,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$RANLIB"; then +else case e in #( + e) if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4712,7 +4773,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then @@ -4734,8 +4796,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_RANLIB"; then +else case e in #( + e) if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4757,7 +4819,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then @@ -4790,8 +4853,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DTC+y} then : printf %s "(cached) " >&6 -else $as_nop - case $DTC in +else case e in #( + e) case $DTC in [\\/]* | ?:[\\/]*) ac_cv_path_DTC="$DTC" # Let the user override the test with a path. ;; @@ -4817,6 +4880,7 @@ IFS=$as_save_IFS test -z "$ac_cv_path_DTC" && ac_cv_path_DTC="no" ;; +esac ;; esac fi DTC=$ac_cv_path_DTC @@ -4872,8 +4936,8 @@ printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_bigendian=unknown +else case e in #( + e) ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4919,8 +4983,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext int main (void) { -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\ && LITTLE_ENDIAN) bogus endian macros #endif @@ -4951,8 +5015,9 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -4996,8 +5061,9 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -5024,22 +5090,23 @@ unsigned short int ascii_mm[] = int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } - extern int foo; - -int -main (void) -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} + int + main (int argc, char **argv) + { + /* Intimidate the compiler so that it does not + optimize the arrays away. */ + char *p = argv[0]; + ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; + ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; + return use_ascii (argc) == use_ebcdic (*p); + } _ACEOF -if ac_fn_cxx_try_compile "$LINENO" +if ac_fn_cxx_try_link "$LINENO" then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then ac_cv_c_bigendian=yes fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else @@ -5048,9 +5115,10 @@ then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -5073,14 +5141,17 @@ _ACEOF if ac_fn_cxx_try_run "$LINENO" then : ac_cv_c_bigendian=no -else $as_nop - ac_cv_c_bigendian=yes +else case e in #( + e) ac_cv_c_bigendian=yes ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - fi + fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } @@ -5129,8 +5200,8 @@ if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS @@ -5184,7 +5255,8 @@ esac IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir - + ;; +esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install @@ -5215,8 +5287,9 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test ${enable_stow+y} then : enableval=$enable_stow; enable_stow="yes" -else $as_nop - enable_stow="no" +else case e in #( + e) enable_stow="no" ;; +esac fi @@ -5233,157 +5306,6 @@ fi #------------------------------------------------------------------------- -# Checks for header files -#------------------------------------------------------------------------- - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf "%s\n" "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -# Autoupdate added the next two lines to ensure that your configure -# script's behavior did not change. They are probably safe to remove. - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - - - -#------------------------------------------------------------------------- # Checks for type #------------------------------------------------------------------------- @@ -5407,14 +5329,14 @@ fi for flag in -Wl,--export-dynamic; do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_ldflags__$flag" | $as_tr_sh` + as_CACHEVAR=`printf "%s\n" "ax_cv_check_ldflags__$flag" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts $flag" >&5 printf %s "checking whether the linker accepts $flag... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $flag" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5431,12 +5353,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$ax_check_save_flags + LDFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -5465,33 +5389,38 @@ then : ;; esac -else $as_nop - +else case e in #( + e) LDFLAGS=$flag { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : LDFLAGS=\"\$LDFLAGS\""; } >&5 (: LDFLAGS="$LDFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } - + ;; +esac fi -else $as_nop - : +else case e in #( + e) : ;; +esac fi done -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -relocatable-pch" >&5 -printf %s "checking whether C++ compiler accepts -relocatable-pch... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler accepts -relocatable-pch" >&5 +printf %s "checking whether the C++ compiler accepts -relocatable-pch... " >&6; } if test ${ax_cv_check_cxxflags___relocatable_pch+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS - CXXFLAGS="$CXXFLAGS -relocatable-pch" + if test x"$GXX" = xyes ; then + add_gnu_werror="-Werror" + fi + CXXFLAGS="$CXXFLAGS -relocatable-pch $add_gnu_werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5506,11 +5435,13 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_check_cxxflags___relocatable_pch=yes -else $as_nop - ax_cv_check_cxxflags___relocatable_pch=no +else case e in #( + e) ax_cv_check_cxxflags___relocatable_pch=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___relocatable_pch" >&5 printf "%s\n" "$ax_cv_check_cxxflags___relocatable_pch" >&6; } @@ -5518,8 +5449,9 @@ if test "x$ax_cv_check_cxxflags___relocatable_pch" = xyes then : HAVE_CLANG_PCH=yes -else $as_nop - : +else case e in #( + e) : ;; +esac fi @@ -5590,8 +5522,8 @@ printf %s "checking for pthread_create in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_create+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5610,12 +5542,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_create=yes -else $as_nop - ac_cv_lib_pthread_pthread_create=no +else case e in #( + e) ac_cv_lib_pthread_pthread_create=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } @@ -5625,8 +5559,9 @@ then : LIBS="-lpthread $LIBS" -else $as_nop - as_fn_error $? "libpthread is required" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "libpthread is required" "$LINENO" 5 ;; +esac fi @@ -5714,8 +5649,9 @@ then : want_boost="yes";_AX_BOOST_BASE_boost_path="$withval" ;; esac -else $as_nop - want_boost="yes" +else case e in #( + e) want_boost="yes" ;; +esac fi @@ -5728,12 +5664,14 @@ then : if test -d "$withval" then : _AX_BOOST_BASE_boost_lib_path="$withval" -else $as_nop - as_fn_error $? "--with-boost-libdir expected directory name" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "--with-boost-libdir expected directory name" "$LINENO" 5 ;; +esac fi -else $as_nop - _AX_BOOST_BASE_boost_lib_path="" +else case e in #( + e) _AX_BOOST_BASE_boost_lib_path="" ;; +esac fi @@ -5746,8 +5684,9 @@ then : if test "x1.53" = "x" then : _AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0" -else $as_nop - _AX_BOOST_BASE_TONUMERICVERSION_req="1.53" +else case e in #( + e) _AX_BOOST_BASE_TONUMERICVERSION_req="1.53" ;; +esac fi _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\.[0-9]*\)'` _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([0-9]*\)'` @@ -5777,7 +5716,7 @@ fi libsubdirs="lib64 libx32 lib lib64" ;; #( mips*64*) : libsubdirs="lib64 lib32 lib lib64" ;; #( - ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k) : + ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k|loongarch64) : libsubdirs="lib64 lib lib64" ;; #( *) : libsubdirs="lib" @@ -5816,25 +5755,27 @@ printf "%s\n" "yes" >&6; } BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; break; -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; +esac fi done -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } +printf "%s\n" "no" >&6; } ;; +esac fi -else $as_nop - +else case e in #( + e) if test X"$cross_compiling" = Xyes; then search_libsubdirs=$multiarch_libsubdir else search_libsubdirs="$multiarch_libsubdir $libsubdirs" fi - for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then for libsubdir in $search_libsubdirs ; do if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi @@ -5844,7 +5785,8 @@ else $as_nop break; fi done - + ;; +esac fi if test "x$_AX_BOOST_BASE_boost_lib_path" != "x" @@ -5936,7 +5878,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu fi else if test "x$cross_compiling" != "xyes" ; then - for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` @@ -6030,6 +5972,8 @@ printf "%s\n" "$as_me: We could not detect the boost libraries (version 1.53 or { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Your boost libraries seems to old (version $_version)." >&5 printf "%s\n" "$as_me: Your boost libraries seems to old (version $_version)." >&6;} fi + BOOST_LDFLAGS="" + BOOST_CPPFLAGS="" # execute ACTION-IF-NOT-FOUND (if present): : else @@ -6064,9 +6008,10 @@ then : ax_boost_user_asio_lib="$withval" fi -else $as_nop - want_boost="yes" - +else case e in #( + e) want_boost="yes" + ;; +esac fi @@ -6085,8 +6030,8 @@ printf %s "checking whether the Boost::ASIO library is available... " >&6; } if test ${ax_cv_boost_asio+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_ext=cpp +else case e in #( + e) ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -6115,8 +6060,9 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_boost_asio=yes -else $as_nop - ax_cv_boost_asio=no +else case e in #( + e) ax_cv_boost_asio=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=cpp @@ -6125,7 +6071,8 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_boost_asio" >&5 printf "%s\n" "$ax_cv_boost_asio" >&6; } @@ -6137,14 +6084,14 @@ printf "%s\n" "#define HAVE_BOOST_ASIO /**/" >>confdefs.h BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/[^\/]*//'` if test "x$ax_boost_user_asio_lib" = "x"; then for ax_lib in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.dylib* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_system.*\)\.a.*$;\1;' ` ; do - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -l$ax_lib" >&5 printf %s "checking for main in -l$ax_lib... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$ax_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6163,12 +6110,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -6176,21 +6125,22 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : BOOST_ASIO_LIB="-l$ax_lib" link_thread="yes" break -else $as_nop - link_thread="no" +else case e in #( + e) link_thread="no" ;; +esac fi done else for ax_lib in $ax_boost_user_asio_lib $BN-$ax_boost_user_asio_lib; do - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -l$ax_lib" >&5 printf %s "checking for main in -l$ax_lib... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$ax_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6209,12 +6159,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -6222,8 +6174,9 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : BOOST_ASIO_LIB="-l$ax_lib" link_asio="yes" break -else $as_nop - link_asio="no" +else case e in #( + e) link_asio="no" ;; +esac fi done @@ -6257,9 +6210,10 @@ then : ax_boost_user_regex_lib="$withval" fi -else $as_nop - want_boost="yes" - +else case e in #( + e) want_boost="yes" + ;; +esac fi @@ -6278,8 +6232,8 @@ printf %s "checking whether the Boost::Regex library is available... " >&6; } if test ${ax_cv_boost_regex+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_ext=cpp +else case e in #( + e) ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -6300,8 +6254,9 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_boost_regex=yes -else $as_nop - ax_cv_boost_regex=no +else case e in #( + e) ax_cv_boost_regex=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=cpp @@ -6310,7 +6265,8 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_boost_regex" >&5 printf "%s\n" "$ax_cv_boost_regex" >&6; } @@ -6322,14 +6278,14 @@ printf "%s\n" "#define HAVE_BOOST_REGEX /**/" >>confdefs.h if test "x$ax_boost_user_regex_lib" = "x"; then for libextension in `ls $BOOSTLIBDIR/libboost_regex*.so* $BOOSTLIBDIR/libboost_regex*.dylib* $BOOSTLIBDIR/libboost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_regex.*\)\.so.*$;\1;' -e 's;^lib\(boost_regex.*\)\.dylib.*;\1;' -e 's;^lib\(boost_regex.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_exit" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_exit" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for exit in -l$ax_lib" >&5 printf %s "checking for exit in -l$ax_lib... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$ax_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6348,12 +6304,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -6361,22 +6319,23 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : BOOST_REGEX_LIB="-l$ax_lib"; link_regex="yes"; break -else $as_nop - link_regex="no" +else case e in #( + e) link_regex="no" ;; +esac fi done if test "x$link_regex" != "xyes"; then for libextension in `ls $BOOSTLIBDIR/boost_regex*.dll* $BOOSTLIBDIR/boost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_regex.*\)\.dll.*$;\1;' -e 's;^\(boost_regex.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_exit" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_exit" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for exit in -l$ax_lib" >&5 printf %s "checking for exit in -l$ax_lib... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$ax_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6395,12 +6354,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -6408,8 +6369,9 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : BOOST_REGEX_LIB="-l$ax_lib"; link_regex="yes"; break -else $as_nop - link_regex="no" +else case e in #( + e) link_regex="no" ;; +esac fi done @@ -6417,14 +6379,14 @@ fi else for ax_lib in $ax_boost_user_regex_lib boost_regex-$ax_boost_user_regex_lib; do - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$ax_lib""_main" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -l$ax_lib" >&5 printf %s "checking for main in -l$ax_lib... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$ax_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6443,12 +6405,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -6456,8 +6420,9 @@ printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : BOOST_REGEX_LIB="-l$ax_lib"; link_regex="yes"; break -else $as_nop - link_regex="no" +else case e in #( + e) link_regex="no" ;; +esac fi done @@ -6480,8 +6445,8 @@ printf %s "checking for main in -lboost_system... " >&6; } if test ${ac_cv_lib_boost_system_main+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_system $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6500,12 +6465,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : ac_cv_lib_boost_system_main=yes -else $as_nop - ac_cv_lib_boost_system_main=no +else case e in #( + e) ac_cv_lib_boost_system_main=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_system_main" >&5 printf "%s\n" "$ac_cv_lib_boost_system_main" >&6; } @@ -6523,8 +6490,8 @@ printf %s "checking for main in -lboost_regex... " >&6; } if test ${ac_cv_lib_boost_regex_main+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lboost_regex $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6543,12 +6510,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : ac_cv_lib_boost_regex_main=yes -else $as_nop - ac_cv_lib_boost_regex_main=no +else case e in #( + e) ac_cv_lib_boost_regex_main=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_boost_regex_main" >&5 printf "%s\n" "$ac_cv_lib_boost_regex_main" >&6; } @@ -6562,44 +6531,17 @@ fi -# Check whether --with-isa was given. -if test ${with_isa+y} -then : - withval=$with_isa; -printf "%s\n" "#define DEFAULT_ISA \"$withval\"" >>confdefs.h - -else $as_nop - -printf "%s\n" "#define DEFAULT_ISA \"RV64IMAFDC_zicntr_zihpm\"" >>confdefs.h - -fi - - - -# Check whether --with-priv was given. -if test ${with_priv+y} -then : - withval=$with_priv; -printf "%s\n" "#define DEFAULT_PRIV \"$withval\"" >>confdefs.h - -else $as_nop - -printf "%s\n" "#define DEFAULT_PRIV \"MSU\"" >>confdefs.h - -fi - - - # Check whether --with-target was given. if test ${with_target+y} then : withval=$with_target; printf "%s\n" "#define TARGET_ARCH \"$withval\"" >>confdefs.h -else $as_nop - +else case e in #( + e) printf "%s\n" "#define TARGET_ARCH \"riscv64-unknown-elf\"" >>confdefs.h - + ;; +esac fi @@ -6608,8 +6550,8 @@ printf %s "checking for library containing dlopen... " >&6; } if test ${ac_cv_search_dlopen+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6646,11 +6588,13 @@ done if test ${ac_cv_search_dlopen+y} then : -else $as_nop - ac_cv_search_dlopen=no +else case e in #( + e) ac_cv_search_dlopen=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 printf "%s\n" "$ac_cv_search_dlopen" >&6; } @@ -6673,8 +6617,8 @@ printf %s "checking for pthread_create in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_create+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6693,12 +6637,14 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_create=yes -else $as_nop - ac_cv_lib_pthread_pthread_create=no +else case e in #( + e) ac_cv_lib_pthread_pthread_create=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } @@ -6708,8 +6654,9 @@ then : LIBS="-lpthread $LIBS" -else $as_nop - as_fn_error $? "libpthread is required" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "libpthread is required" "$LINENO" 5 ;; +esac fi @@ -7044,8 +6991,8 @@ cat >confcache <<\_ACEOF # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the +# 'ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF @@ -7075,14 +7022,14 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote + # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) - # `set' quotes correctly as required by POSIX, so do not add quotes. + # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | @@ -7173,7 +7120,6 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -7182,12 +7128,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -7259,7 +7206,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -7288,7 +7235,6 @@ as_fn_error () } # as_fn_error - # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -7328,11 +7274,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -7346,11 +7293,12 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith @@ -7433,9 +7381,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -7516,10 +7464,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 @@ -7535,7 +7485,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by RISC-V ISA Simulator $as_me ?, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -7566,7 +7516,7 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions +'$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -7599,10 +7549,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ RISC-V ISA Simulator config.status ? -configured by $0, generated by GNU Autoconf 2.71, +configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -7662,8 +7612,8 @@ do ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; + as_fn_error $? "ambiguous option: '$1' +Try '$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ @@ -7671,8 +7621,8 @@ Try \`$0 --help' for more information.";; ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -7734,7 +7684,7 @@ do "riscv-disasm.pc") CONFIG_FILES="$CONFIG_FILES riscv-disasm.pc" ;; "riscv-riscv.pc") CONFIG_FILES="$CONFIG_FILES riscv-riscv.pc" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done @@ -7753,7 +7703,7 @@ fi # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. +# after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= @@ -7777,7 +7727,7 @@ ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. +# This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then @@ -7935,13 +7885,13 @@ fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. +# This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF -# Transform confdefs.h into an awk script `defines.awk', embedded as +# Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. @@ -8051,7 +8001,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -8073,19 +8023,19 @@ do -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. + # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is `configure' which instantiates (i.e., don't + # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` @@ -8213,7 +8163,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 esac _ACEOF -# Neutralize VPATH when `$srcdir' = `.'. +# Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -8243,9 +8193,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" diff --git a/configure.ac b/configure.ac index 701bd99..e007335 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ #========================================================================= # Toplevel configure.ac for the Modular C++ Build System #========================================================================= -# Please read the documenation in 'mcppbs-doc.txt' for more details on +# Please read the documentation in 'mcppbs-doc.txt' for more details on # how the Modular C++ Build System works. For most new projects, a # developer will only need to make the following changes: # @@ -36,21 +36,21 @@ m4_define( proj_version, [?]) # Setup #------------------------------------------------------------------------- -AC_INIT(proj_name,proj_version,proj_maintainer,proj_abbreviation) -AC_LANG_CPLUSPLUS +AC_INIT([proj_name],[proj_version],[proj_maintainer],[proj_abbreviation]) +AC_LANG([C++]) AC_CONFIG_SRCDIR([riscv/common.h]) AC_CONFIG_AUX_DIR([scripts]) AC_CANONICAL_BUILD AC_CANONICAL_HOST -m4_include(ax_require_defined.m4) -m4_include(ax_append_flag.m4) -m4_include(ax_check_compile_flag.m4) -m4_include(ax_check_link_flag.m4) -m4_include(ax_append_link_flags.m4) -m4_include(ax_boost_base.m4) -m4_include(ax_boost_asio.m4) -m4_include(ax_boost_regex.m4) +m4_include(m4/ax_require_defined.m4) +m4_include(m4/ax_append_flag.m4) +m4_include(m4/ax_check_compile_flag.m4) +m4_include(m4/ax_check_link_flag.m4) +m4_include(m4/ax_append_link_flags.m4) +m4_include(m4/ax_boost_base.m4) +m4_include(m4/ax_boost_asio.m4) +m4_include(m4/ax_boost_regex.m4) #------------------------------------------------------------------------- # Checks for programs @@ -76,12 +76,6 @@ AC_C_BIGENDIAN MCPPBS_PROG_INSTALL #------------------------------------------------------------------------- -# Checks for header files -#------------------------------------------------------------------------- - -AC_HEADER_STDC - -#------------------------------------------------------------------------- # Checks for type #------------------------------------------------------------------------- diff --git a/customext/cflush.cc b/customext/cflush.cc index 485716a..c090e88 100644 --- a/customext/cflush.cc +++ b/customext/cflush.cc @@ -19,23 +19,23 @@ static reg_t custom_cflush(processor_t* p, insn_t insn, reg_t pc) class cflush_t : public extension_t { public: - const char* name() { return "cflush"; } + const char* name() const override { return "cflush"; } cflush_t() {} - std::vector<insn_desc_t> get_instructions() { - std::vector<insn_desc_t> insns; - insns.push_back((insn_desc_t){0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); - insns.push_back((insn_desc_t){0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); - insns.push_back((insn_desc_t){0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); + std::vector<insn_desc_t> get_instructions(const processor_t &) override { + std::vector<insn_desc_t> insns = { + {0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}, + {0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}, + {0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}}; return insns; } - std::vector<disasm_insn_t*> get_disasms() { - std::vector<disasm_insn_t*> insns; - insns.push_back(new disasm_insn_t("cflush.d.l1", 0xFC000073, 0xFFF07FFF, {&xrs1})); - insns.push_back(new disasm_insn_t("cdiscard.d.l1", 0xFC200073, 0xFFF07FFF, {&xrs1})); - insns.push_back(new disasm_insn_t("cflush.i.l1", 0xFC100073, 0xFFF07FFF, {&xrs1})); + std::vector<disasm_insn_t *> get_disasms(const processor_t *) override { + std::vector<disasm_insn_t*> insns = { + new disasm_insn_t("cflush.d.l1", 0xFC000073, 0xFFF07FFF, {&xrs1}), + new disasm_insn_t("cdiscard.d.l1", 0xFC200073, 0xFFF07FFF, {&xrs1}), + new disasm_insn_t("cflush.i.l1", 0xFC100073, 0xFFF07FFF, {&xrs1})}; return insns; } }; diff --git a/customext/dummy_rocc.cc b/customext/dummy_rocc.cc index 8c051fa..6669887 100644 --- a/customext/dummy_rocc.cc +++ b/customext/dummy_rocc.cc @@ -5,14 +5,14 @@ class dummy_rocc_t : public rocc_t { public: - const char* name() { return "dummy_rocc"; } + const char* name() const { return "dummy_rocc"; } - reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t UNUSED xs2) + reg_t custom0(processor_t *p, rocc_insn_t insn, reg_t xs1, reg_t UNUSED xs2) { reg_t prev_acc = acc[insn.rs2]; if (insn.rs2 >= num_acc) - illegal_instruction(); + illegal_instruction(*p); switch (insn.funct) { @@ -28,7 +28,7 @@ class dummy_rocc_t : public rocc_t acc[insn.rs2] += xs1; break; default: - illegal_instruction(); + illegal_instruction(*p); } return prev_acc; // in all cases, xd <- previous value of acc[rs2] diff --git a/debug_rom/debug_rom.S b/debug_rom/debug_rom.S index 2d36139..378c568 100755 --- a/debug_rom/debug_rom.S +++ b/debug_rom/debug_rom.S @@ -7,6 +7,19 @@ .global entry .global exception +// This macro handles mem access with proper management of the MPRVEN +// Usage: MEMORY_ACCESS_WITH_MPRV(<your code>) +#define MEMORY_ACCESS_WITH_MPRV(...) \ + csrrci s0, CSR_DCSR, DCSR_MPRVEN; \ + andi s0, s0, DCSR_MPRVEN; \ + bnez s0, 1f; \ + __VA_ARGS__; \ + j 2f; \ +1: \ + __VA_ARGS__; \ + csrrsi zero, CSR_DCSR, DCSR_MPRVEN; \ +2: + // Entry location on ebreak, Halt, or Breakpoint // It is the same for all harts. They branch when // their GO or RESUME bit is set. @@ -30,13 +43,22 @@ _entry: // We keep checking both whether there is something the debugger wants // us to do, or whether we should resume. entry_loop: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_HALTED(zero) - lbu s0, DEBUG_ROM_FLAGS(s0) // 1 byte flag per hart. Only one hart advances here. + // 1 byte flag per hart. Only one hart advances here. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_HALTED(zero); + lbu s0, DEBUG_ROM_FLAGS(s0); + ) + andi s0, s0, (1 << DEBUG_ROM_FLAG_GO) bnez s0, going - csrr s0, CSR_MHARTID - lbu s0, DEBUG_ROM_FLAGS(s0) // multiple harts can resume here + + // multiple harts can resume here + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + lbu s0, DEBUG_ROM_FLAGS(s0); + ) + andi s0, s0, (1 << DEBUG_ROM_FLAG_RESUME) bnez s0, _resume wfi @@ -46,13 +68,23 @@ _exception: // Restore S0, which we always save to dscratch. // We need this in case the user tried an abstract write to a // non-existent CSR. - csrr s0, CSR_DSCRATCH0 - sw zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception. + + + // Let debug module know you got an exception. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_DSCRATCH0; + sw zero, DEBUG_ROM_EXCEPTION(zero); + ) + ebreak going: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_GOING(zero) // When debug module sees this write, the GO flag is reset. + // When debug module sees this write, the GO flag is reset. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_GOING(zero); + ) + csrr s0, CSR_DSCRATCH0 // Restore s0 here fence fence.i @@ -61,8 +93,12 @@ going: // because jalr is special there) _resume: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset. + // When Debug Module sees this write, the RESUME flag is reset. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_RESUMING(zero); + ) + csrr s0, CSR_DSCRATCH0 // Restore s0 dret diff --git a/debug_rom/debug_rom.h b/debug_rom/debug_rom.h index 7edd5f6..d3d89a2 100644 --- a/debug_rom/debug_rom.h +++ b/debug_rom/debug_rom.h @@ -1,13 +1,25 @@ static const unsigned char debug_rom_raw[] = { - 0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x00, 0x06, 0x6f, 0x00, 0x80, 0x03, - 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1, - 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00, - 0x63, 0x14, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, - 0x13, 0x74, 0x24, 0x00, 0x63, 0x18, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10, - 0x6f, 0xf0, 0x9f, 0xfd, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, - 0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x22, 0x80, 0x10, - 0x73, 0x24, 0x20, 0x7b, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, + 0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x40, 0x0d, 0x6f, 0x00, 0x40, 0x07, + 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x74, 0x08, 0x7b, + 0x13, 0x74, 0x04, 0x01, 0x63, 0x1a, 0x04, 0x00, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x6f, 0x00, 0x40, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, + 0x73, 0x60, 0x08, 0x7b, 0x13, 0x74, 0x14, 0x00, 0x63, 0x10, 0x04, 0x06, + 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, + 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, 0x6f, 0x00, 0x00, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, 0x73, 0x60, 0x08, 0x7b, + 0x13, 0x74, 0x24, 0x00, 0x63, 0x14, 0x04, 0x06, 0x73, 0x00, 0x50, 0x10, + 0x6f, 0xf0, 0xdf, 0xf9, 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, + 0x63, 0x18, 0x04, 0x00, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, + 0x6f, 0x00, 0x00, 0x01, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, + 0x73, 0x60, 0x08, 0x7b, 0x73, 0x00, 0x10, 0x00, 0x73, 0x74, 0x08, 0x7b, + 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x22, 0x80, 0x10, 0x6f, 0x00, 0x00, 0x01, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x22, 0x80, 0x10, 0x73, 0x60, 0x08, 0x7b, 0x73, 0x24, 0x20, 0x7b, + 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, 0x67, 0x00, 0x00, 0x30, + 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x6f, 0x00, 0x00, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x73, 0x60, 0x08, 0x7b, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b }; -static const unsigned int debug_rom_raw_len = 116; +static const unsigned int debug_rom_raw_len = 260; diff --git a/disasm/disasm.cc b/disasm/disasm.cc index c3ba62a..49f2794 100644 --- a/disasm/disasm.cc +++ b/disasm/disasm.cc @@ -2,6 +2,7 @@ #include "disasm.h" #include "decode_macros.h" +#include "platform.h" #include <cassert> #include <string> #include <vector> @@ -705,44 +706,39 @@ static void NOINLINE add_sfence_insn(disassembler_t* d, const char* name, uint32 d->add_insn(new disasm_insn_t(name, match, mask, {&xrs1, &xrs2})); } -static void NOINLINE add_pitype3_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_v_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm3})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, opt, &vm})); } -static void NOINLINE add_pitype4_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_vv_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm4})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &vs1, opt, &vm})); } -static void NOINLINE add_pitype5_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_multiplyadd_vv_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm5})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs1, &vs2, opt, &vm})); } -static void NOINLINE add_pitype6_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_vx_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm6})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &xrs1, opt, &vm})); } -static void NOINLINE add_vector_v_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_multiplyadd_vx_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, opt, &vm})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &xrs1, &vs2, opt, &vm})); } -static void NOINLINE add_vector_vv_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_vf_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &vs1, opt, &vm})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &frs1, opt, &vm})); } -static void NOINLINE add_vector_vx_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) +static void NOINLINE add_vector_multiplyadd_vf_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { - d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &xrs1, opt, &vm})); -} - -static void NOINLINE add_vector_vf_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) -{ - d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &frs1, opt, &vm})); + d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &frs1, &vs2, opt, &vm})); } static void NOINLINE add_vector_vi_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) @@ -793,7 +789,12 @@ static void NOINLINE add_unknown_insns(disassembler_t* d) #undef DECLARE_INSN } -void disassembler_t::add_instructions(const isa_parser_t* isa) +#define ext_enabled_strict(x) (isa->extension_enabled(x)) +#define ext_enabled(x) (ext_enabled_strict(x) || !strict) +#define xlen_eq(x) (xlen_eq_strict(x) || !strict) +#define xlen_eq_strict(x) (isa->get_max_xlen() == (x)) + +void disassembler_t::add_instructions(const isa_parser_t* isa, bool strict) { const uint32_t mask_rd = 0x1fUL << 7; const uint32_t match_rd_ra = 1UL << 7; @@ -866,16 +867,19 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_XLOAD(lh) DEFINE_XLOAD(lhu) DEFINE_XLOAD(lw) - DEFINE_XLOAD(lwu) - DEFINE_XLOAD(ld) DEFINE_XSTORE(sb) DEFINE_XSTORE(sh) DEFINE_XSTORE(sw) - DEFINE_XSTORE(sd) - if (isa->extension_enabled('A') || - isa->extension_enabled(EXT_ZAAMO)) { + if (xlen_eq(64)) { + DEFINE_XLOAD(lwu) + DEFINE_XLOAD(ld) + + DEFINE_XSTORE(sd) + } + + if (ext_enabled(EXT_ZAAMO)) { DEFINE_XAMO(amoadd_w) DEFINE_XAMO(amoswap_w) DEFINE_XAMO(amoand_w) @@ -885,32 +889,39 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_XAMO(amomax_w) DEFINE_XAMO(amominu_w) DEFINE_XAMO(amomaxu_w) - DEFINE_XAMO(amoadd_d) - DEFINE_XAMO(amoswap_d) - DEFINE_XAMO(amoand_d) - DEFINE_XAMO(amoor_d) - DEFINE_XAMO(amoxor_d) - DEFINE_XAMO(amomin_d) - DEFINE_XAMO(amomax_d) - DEFINE_XAMO(amominu_d) - DEFINE_XAMO(amomaxu_d) - } - - if (isa->extension_enabled('A') || - isa->extension_enabled(EXT_ZALRSC)) { + + if (xlen_eq(64)) { + DEFINE_XAMO(amoadd_d) + DEFINE_XAMO(amoswap_d) + DEFINE_XAMO(amoand_d) + DEFINE_XAMO(amoor_d) + DEFINE_XAMO(amoxor_d) + DEFINE_XAMO(amomin_d) + DEFINE_XAMO(amomax_d) + DEFINE_XAMO(amominu_d) + DEFINE_XAMO(amomaxu_d) + } + } + + if (ext_enabled(EXT_ZALRSC)) { DEFINE_XLOAD_BASE(lr_w) DEFINE_XAMO(sc_w) - DEFINE_XLOAD_BASE(lr_d) - DEFINE_XAMO(sc_d) + + if (xlen_eq(64)) { + DEFINE_XLOAD_BASE(lr_d) + DEFINE_XAMO(sc_d) + } } - if (isa->extension_enabled(EXT_ZACAS)) { + if (ext_enabled(EXT_ZACAS)) { DEFINE_XAMO(amocas_w) DEFINE_XAMO(amocas_d) - DEFINE_XAMO(amocas_q) + + if (xlen_eq(64)) + DEFINE_XAMO(amocas_q) } - if (isa->extension_enabled(EXT_ZABHA)) { + if (ext_enabled(EXT_ZABHA)) { DEFINE_XAMO(amoadd_b) DEFINE_XAMO(amoswap_b) DEFINE_XAMO(amoand_b) @@ -933,12 +944,12 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_XAMO(amocas_h) } - if (isa->extension_enabled(EXT_ZAWRS)) { + if (ext_enabled(EXT_ZAWRS)) { DEFINE_NOARG(wrs_sto); DEFINE_NOARG(wrs_nto); } - if (isa->extension_enabled(EXT_ZICFILP)) { + if (ext_enabled(EXT_ZICFILP)) { // lpad encodes as `auipc x0, label`, so it needs to be added before auipc // for higher disassembling priority DISASM_INSN("lpad", lpad, 0, {&bigimm}); @@ -983,12 +994,21 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_ITYPE(ori); DEFINE_ITYPE(andi); - DEFINE_I1TYPE("sext.w", addiw); - DEFINE_ITYPE(addiw); - DEFINE_ITYPE_SHIFT(slliw); - DEFINE_ITYPE_SHIFT(srliw); - DEFINE_ITYPE_SHIFT(sraiw); + if (xlen_eq(64)) { + DEFINE_I1TYPE("sext.w", addiw); + DEFINE_ITYPE(addiw); + + DEFINE_ITYPE_SHIFT(slliw); + DEFINE_ITYPE_SHIFT(srliw); + DEFINE_ITYPE_SHIFT(sraiw); + + DEFINE_RTYPE(addw); + DEFINE_RTYPE(subw); + DEFINE_RTYPE(sllw); + DEFINE_RTYPE(srlw); + DEFINE_RTYPE(sraw); + } DEFINE_RTYPE(add); DEFINE_RTYPE(sub); @@ -1001,11 +1021,6 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_RTYPE(sra); DEFINE_RTYPE(or); DEFINE_RTYPE(and); - DEFINE_RTYPE(addw); - DEFINE_RTYPE(subw); - DEFINE_RTYPE(sllw); - DEFINE_RTYPE(srlw); - DEFINE_RTYPE(sraw); DEFINE_NOARG(ecall); DEFINE_NOARG(ebreak); @@ -1029,32 +1044,35 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) add_insn(new disasm_insn_t("csrrsi", match_csrrsi, mask_csrrsi, {&xrd, &csr, &zimm5})); add_insn(new disasm_insn_t("csrrci", match_csrrci, mask_csrrci, {&xrd, &csr, &zimm5})); - if (isa->extension_enabled('S')) { + if (ext_enabled('S')) { DEFINE_NOARG(sret); DEFINE_SFENCE_TYPE(sfence_vma); } - if (isa->extension_enabled('M')) { + if (ext_enabled('M')) { DEFINE_RTYPE(mul); DEFINE_RTYPE(mulh); DEFINE_RTYPE(mulhu); DEFINE_RTYPE(mulhsu); - DEFINE_RTYPE(mulw); DEFINE_RTYPE(div); DEFINE_RTYPE(divu); DEFINE_RTYPE(rem); DEFINE_RTYPE(remu); - DEFINE_RTYPE(divw); - DEFINE_RTYPE(divuw); - DEFINE_RTYPE(remw); - DEFINE_RTYPE(remuw); + + if (xlen_eq(64)) { + DEFINE_RTYPE(mulw); + DEFINE_RTYPE(divw); + DEFINE_RTYPE(divuw); + DEFINE_RTYPE(remw); + DEFINE_RTYPE(remuw); + } } - if (isa->extension_enabled(EXT_ZBA)) { + if (ext_enabled(EXT_ZBA)) { DEFINE_RTYPE(sh1add); DEFINE_RTYPE(sh2add); DEFINE_RTYPE(sh3add); - if (isa->get_max_xlen() == 64) { + if (xlen_eq(64)) { DEFINE_ITYPE_SHIFT(slli_uw); add_insn(new disasm_insn_t("zext.w", match_add_uw, mask_add_uw | mask_rs2, {&xrd, &xrs1})); DEFINE_RTYPE(add_uw); @@ -1064,7 +1082,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } } - if (isa->extension_enabled(EXT_ZBB)) { + if (ext_enabled(EXT_ZBB)) { DEFINE_RTYPE(ror); DEFINE_RTYPE(rol); DEFINE_ITYPE_SHIFT(rori); @@ -1083,7 +1101,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) add_insn(new disasm_insn_t("rev8", match_grevi | ((isa->get_max_xlen() - 8) << imm_shift), mask_grevi | mask_imm, {&xrd, &xrs1})); add_insn(new disasm_insn_t("orc.b", match_gorci | (0x7 << imm_shift), mask_grevi | mask_imm, {&xrd, &xrs1})); add_insn(new disasm_insn_t("zext.h", (isa->get_max_xlen() == 32 ? match_pack : match_packw), mask_pack | mask_rs2, {&xrd, &xrs1})); - if (isa->get_max_xlen() == 64) { + if (xlen_eq(64)) { DEFINE_RTYPE(rorw); DEFINE_RTYPE(rolw); DEFINE_ITYPE_SHIFT(roriw); @@ -1093,13 +1111,13 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } } - if (isa->extension_enabled(EXT_ZBC)) { + if (ext_enabled(EXT_ZBC)) { DEFINE_RTYPE(clmul); DEFINE_RTYPE(clmulh); DEFINE_RTYPE(clmulr); } - if (isa->extension_enabled(EXT_ZBS)) { + if (ext_enabled(EXT_ZBS)) { DEFINE_RTYPE(bclr); DEFINE_RTYPE(binv); DEFINE_RTYPE(bset); @@ -1110,17 +1128,17 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_ITYPE_SHIFT(bexti); } - if (isa->extension_enabled(EXT_ZBKB)) { + if (ext_enabled(EXT_ZBKB)) { add_insn(new disasm_insn_t("brev8", match_grevi | (0x7 << imm_shift), mask_grevi | mask_imm, {&xrd, &xrs1})); // brev8 add_insn(new disasm_insn_t("rev8", match_grevi | ((isa->get_max_xlen() - 8) << imm_shift), mask_grevi | mask_imm, {&xrd, &xrs1})); DEFINE_RTYPE(pack); DEFINE_RTYPE(packh); - if (isa->get_max_xlen() == 64) { + if (xlen_eq(64)) { DEFINE_RTYPE(packw); } } - if (isa->extension_enabled(EXT_SVINVAL)) { + if (ext_enabled(EXT_SVINVAL)) { DEFINE_NOARG(sfence_w_inval); DEFINE_NOARG(sfence_inval_ir); DEFINE_SFENCE_TYPE(sinval_vma); @@ -1128,9 +1146,14 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_SFENCE_TYPE(hinval_gvma); } - if (isa->extension_enabled('F')) { + if (ext_enabled('F')) { DEFINE_FLOAD(flw) DEFINE_FSTORE(fsw) + DEFINE_XFTYPE(fmv_w_x); + DEFINE_FXTYPE(fmv_x_w); + } + + if (ext_enabled('F') || ext_enabled(EXT_ZFINX)) { DEFINE_FRTYPE(fadd_s); DEFINE_FRTYPE(fsub_s); DEFINE_FRTYPE(fmul_s); @@ -1147,58 +1170,35 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FRTYPE(fsgnjx_s); DEFINE_FR1TYPE(fcvt_s_d); DEFINE_FR1TYPE(fcvt_s_q); - DEFINE_XFTYPE(fcvt_s_l); - DEFINE_XFTYPE(fcvt_s_lu); DEFINE_XFTYPE(fcvt_s_w); DEFINE_XFTYPE(fcvt_s_wu); DEFINE_XFTYPE(fcvt_s_wu); - DEFINE_XFTYPE(fmv_w_x); - DEFINE_FXTYPE(fcvt_l_s); - DEFINE_FXTYPE(fcvt_lu_s); DEFINE_FXTYPE(fcvt_w_s); DEFINE_FXTYPE(fcvt_wu_s); DEFINE_FXTYPE(fclass_s); - DEFINE_FXTYPE(fmv_x_w); DEFINE_FX2TYPE(feq_s); DEFINE_FX2TYPE(flt_s); DEFINE_FX2TYPE(fle_s); + + if (xlen_eq(64)) { + DEFINE_XFTYPE(fcvt_s_l); + DEFINE_XFTYPE(fcvt_s_lu); + DEFINE_FXTYPE(fcvt_l_s); + DEFINE_FXTYPE(fcvt_lu_s); + } } - if (isa->extension_enabled(EXT_ZFINX)) { - DEFINE_RTYPE(fadd_s); - DEFINE_RTYPE(fsub_s); - DEFINE_RTYPE(fmul_s); - DEFINE_RTYPE(fdiv_s); - DEFINE_R1TYPE(fsqrt_s); - DEFINE_RTYPE(fmin_s); - DEFINE_RTYPE(fmax_s); - DEFINE_R3TYPE(fmadd_s); - DEFINE_R3TYPE(fmsub_s); - DEFINE_R3TYPE(fnmadd_s); - DEFINE_R3TYPE(fnmsub_s); - DEFINE_RTYPE(fsgnj_s); - DEFINE_RTYPE(fsgnjn_s); - DEFINE_RTYPE(fsgnjx_s); - DEFINE_R1TYPE(fcvt_s_d); - //DEFINE_R1TYPE(fcvt_s_q); - DEFINE_R1TYPE(fcvt_s_l); - DEFINE_R1TYPE(fcvt_s_lu); - DEFINE_R1TYPE(fcvt_s_w); - DEFINE_R1TYPE(fcvt_s_wu); - DEFINE_R1TYPE(fcvt_s_wu); - DEFINE_R1TYPE(fcvt_l_s); - DEFINE_R1TYPE(fcvt_lu_s); - DEFINE_R1TYPE(fcvt_w_s); - DEFINE_R1TYPE(fcvt_wu_s); - DEFINE_R1TYPE(fclass_s); - DEFINE_RTYPE(feq_s); - DEFINE_RTYPE(flt_s); - DEFINE_RTYPE(fle_s); - } - - if (isa->extension_enabled('D')) { + if (ext_enabled('D')) { DEFINE_FLOAD(fld) DEFINE_FSTORE(fsd) + + if (xlen_eq(64)) { + DEFINE_XFTYPE(fmv_d_x); + DEFINE_FXTYPE(fmv_x_d); + } + } + + if (ext_enabled('D') || ext_enabled(EXT_ZDINX)) { DEFINE_FRTYPE(fadd_d); DEFINE_FRTYPE(fsub_d); DEFINE_FRTYPE(fmul_d); @@ -1215,24 +1215,25 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FRTYPE(fsgnjx_d); DEFINE_FR1TYPE(fcvt_d_s); DEFINE_FR1TYPE(fcvt_d_q); - DEFINE_XFTYPE(fcvt_d_l); - DEFINE_XFTYPE(fcvt_d_lu); DEFINE_XFTYPE(fcvt_d_w); DEFINE_XFTYPE(fcvt_d_wu); DEFINE_XFTYPE(fcvt_d_wu); - DEFINE_XFTYPE(fmv_d_x); - DEFINE_FXTYPE(fcvt_l_d); - DEFINE_FXTYPE(fcvt_lu_d); DEFINE_FXTYPE(fcvt_w_d); DEFINE_FXTYPE(fcvt_wu_d); DEFINE_FXTYPE(fclass_d); - DEFINE_FXTYPE(fmv_x_d); DEFINE_FX2TYPE(feq_d); DEFINE_FX2TYPE(flt_d); DEFINE_FX2TYPE(fle_d); + + if (xlen_eq(64)) { + DEFINE_XFTYPE(fcvt_d_l); + DEFINE_XFTYPE(fcvt_d_lu); + DEFINE_FXTYPE(fcvt_l_d); + DEFINE_FXTYPE(fcvt_lu_d); + } } - if (isa->extension_enabled(EXT_ZFA)) { + if (ext_enabled(EXT_ZFA)) { DEFINE_FLITYPE(fli_s); DEFINE_FRTYPE(fminm_s); DEFINE_FRTYPE(fmaxm_s); @@ -1241,7 +1242,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fleq_s); DEFINE_FX2TYPE(fltq_s); - if (isa->extension_enabled(EXT_ZFH) || isa->extension_enabled(EXT_ZVFH)) { + if (ext_enabled(EXT_ZFH) || ext_enabled(EXT_ZVFH)) { DEFINE_FLITYPE(fli_h); DEFINE_FRTYPE(fminm_h); DEFINE_FRTYPE(fmaxm_h); @@ -1251,7 +1252,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fltq_h); } - if (isa->extension_enabled('D')) { + if (ext_enabled('D')) { DEFINE_FLITYPE(fli_d); DEFINE_FRTYPE(fminm_d); DEFINE_FRTYPE(fmaxm_d); @@ -1260,13 +1261,13 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fleq_d); DEFINE_FX2TYPE(fltq_d); - if (isa->get_max_xlen() == 32) { + if (xlen_eq(32)) { DEFINE_XF2TYPE(fmvp_d_x); DEFINE_FXTYPE(fmvh_x_d); } } - if (isa->extension_enabled('Q')) { + if (ext_enabled('Q')) { DEFINE_FLITYPE(fli_q); DEFINE_FRTYPE(fminm_q); DEFINE_FRTYPE(fmaxm_q); @@ -1275,46 +1276,14 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fleq_q); DEFINE_FX2TYPE(fltq_q); - if (isa->get_max_xlen() == 64) { + if (xlen_eq(64)) { DEFINE_XF2TYPE(fmvp_q_x); DEFINE_FXTYPE(fmvh_x_q); } } } - if (isa->extension_enabled(EXT_ZDINX)) { - DEFINE_RTYPE(fadd_d); - DEFINE_RTYPE(fsub_d); - DEFINE_RTYPE(fmul_d); - DEFINE_RTYPE(fdiv_d); - DEFINE_R1TYPE(fsqrt_d); - DEFINE_RTYPE(fmin_d); - DEFINE_RTYPE(fmax_d); - DEFINE_R3TYPE(fmadd_d); - DEFINE_R3TYPE(fmsub_d); - DEFINE_R3TYPE(fnmadd_d); - DEFINE_R3TYPE(fnmsub_d); - DEFINE_RTYPE(fsgnj_d); - DEFINE_RTYPE(fsgnjn_d); - DEFINE_RTYPE(fsgnjx_d); - DEFINE_R1TYPE(fcvt_d_s); - //DEFINE_R1TYPE(fcvt_d_q); - DEFINE_R1TYPE(fcvt_d_l); - DEFINE_R1TYPE(fcvt_d_lu); - DEFINE_R1TYPE(fcvt_d_w); - DEFINE_R1TYPE(fcvt_d_wu); - DEFINE_R1TYPE(fcvt_d_wu); - DEFINE_R1TYPE(fcvt_l_d); - DEFINE_R1TYPE(fcvt_lu_d); - DEFINE_R1TYPE(fcvt_w_d); - DEFINE_R1TYPE(fcvt_wu_d); - DEFINE_R1TYPE(fclass_d); - DEFINE_RTYPE(feq_d); - DEFINE_RTYPE(flt_d); - DEFINE_RTYPE(fle_d); - } - - if (isa->extension_enabled(EXT_ZFH)) { + if (ext_enabled(EXT_ZFH)) { DEFINE_FRTYPE(fadd_h); DEFINE_FRTYPE(fsub_h); DEFINE_FRTYPE(fmul_h); @@ -1344,7 +1313,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fle_h); } - if (isa->extension_enabled(EXT_ZHINX)) { + if (ext_enabled(EXT_ZHINX)) { DEFINE_RTYPE(fadd_h); DEFINE_RTYPE(fsub_h); DEFINE_RTYPE(fmul_h); @@ -1374,7 +1343,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_RTYPE(fle_h); } - if (isa->extension_enabled(EXT_ZFHMIN)) { + if (ext_enabled(EXT_ZFHMIN)) { DEFINE_FR1TYPE(fcvt_h_s); DEFINE_FR1TYPE(fcvt_h_d); DEFINE_FR1TYPE(fcvt_h_q); @@ -1383,14 +1352,14 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FR1TYPE(fcvt_q_h); } - if (isa->extension_enabled(EXT_INTERNAL_ZFH_MOVE)) { + if (ext_enabled(EXT_INTERNAL_ZFH_MOVE)) { DEFINE_FLOAD(flh) DEFINE_FSTORE(fsh) DEFINE_XFTYPE(fmv_h_x); DEFINE_FXTYPE(fmv_x_h); } - if (isa->extension_enabled(EXT_ZHINXMIN)) { + if (ext_enabled(EXT_ZHINXMIN)) { DEFINE_R1TYPE(fcvt_h_s); DEFINE_R1TYPE(fcvt_h_d); //DEFINE_R1TYPE(fcvt_h_q); @@ -1399,7 +1368,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) //DEFINE_R1TYPE(fcvt_q_h); } - if (isa->extension_enabled('Q')) { + if (ext_enabled('Q')) { DEFINE_FLOAD(flq) DEFINE_FSTORE(fsq) DEFINE_FRTYPE(fadd_q); @@ -1433,13 +1402,13 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_FX2TYPE(fle_q); } - if (isa->extension_enabled(EXT_ZFBFMIN)) { + if (ext_enabled(EXT_ZFBFMIN)) { DEFINE_FR1TYPE(fcvt_bf16_s); DEFINE_FR1TYPE(fcvt_s_bf16); } // ext-h - if (isa->extension_enabled('H')) { + if (ext_enabled('H')) { DEFINE_XLOAD_BASE(hlv_b) DEFINE_XLOAD_BASE(hlv_bu) DEFINE_XLOAD_BASE(hlv_h) @@ -1461,7 +1430,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } // ext-c - if (isa->extension_enabled(EXT_ZCA)) { + if (ext_enabled(EXT_ZCA)) { DISASM_INSN("c.ebreak", c_add, mask_rd | mask_rvc_rs2, {}); add_insn(new disasm_insn_t("ret", match_c_jr | match_rd_ra, mask_c_jr | mask_rd | mask_rvc_imm, {})); DISASM_INSN("c.jr", c_jr, mask_rvc_imm, {&rvc_rs1}); @@ -1478,9 +1447,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("c.andi", c_andi, 0, {&rvc_rs1s, &rvc_imm}); DISASM_INSN("c.mv", c_mv, 0, {&xrd, &rvc_rs2}); DISASM_INSN("c.add", c_add, 0, {&xrd, &rvc_rs2}); - DISASM_INSN("c.addw", c_addw, 0, {&rvc_rs1s, &rvc_rs2s}); DISASM_INSN("c.sub", c_sub, 0, {&rvc_rs1s, &rvc_rs2s}); - DISASM_INSN("c.subw", c_subw, 0, {&rvc_rs1s, &rvc_rs2s}); DISASM_INSN("c.and", c_and, 0, {&rvc_rs1s, &rvc_rs2s}); DISASM_INSN("c.or", c_or, 0, {&rvc_rs1s, &rvc_rs2s}); DISASM_INSN("c.xor", c_xor, 0, {&rvc_rs1s, &rvc_rs2s}); @@ -1491,13 +1458,18 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("c.beqz", c_beqz, 0, {&rvc_rs1s, &rvc_branch_target}); DISASM_INSN("c.bnez", c_bnez, 0, {&rvc_rs1s, &rvc_branch_target}); DISASM_INSN("c.j", c_j, 0, {&rvc_jump_target}); - if (isa->get_max_xlen() == 32) { + if (xlen_eq_strict(32)) { DISASM_INSN("c.jal", c_jal, 0, {&rvc_jump_target}); } else { DISASM_INSN("c.addiw", c_addiw, 0, {&xrd, &rvc_imm}); } - if (isa->get_max_xlen() == 64 || isa->extension_enabled(EXT_ZCMLSD)) { + if (xlen_eq(64)) { + DISASM_INSN("c.addw", c_addw, 0, {&rvc_rs1s, &rvc_rs2s}); + DISASM_INSN("c.subw", c_subw, 0, {&rvc_rs1s, &rvc_rs2s}); + } + + if (xlen_eq_strict(64) || ext_enabled_strict(EXT_ZCLSD)) { DISASM_INSN("c.ld", c_ld, 0, {&rvc_rs2s, &rvc_ld_address}); DISASM_INSN("c.ldsp", c_ldsp, 0, {&xrd, &rvc_ldsp_address}); DISASM_INSN("c.sd", c_sd, 0, {&rvc_rs2s, &rvc_ld_address}); @@ -1505,26 +1477,26 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } } - if (isa->extension_enabled(EXT_ZCD) && isa->extension_enabled('D')) { + if (ext_enabled(EXT_ZCD)) { DISASM_INSN("c.fld", c_fld, 0, {&rvc_fp_rs2s, &rvc_ld_address}); DISASM_INSN("c.fldsp", c_fldsp, 0, {&frd, &rvc_ldsp_address}); DISASM_INSN("c.fsd", c_fsd, 0, {&rvc_fp_rs2s, &rvc_ld_address}); DISASM_INSN("c.fsdsp", c_fsdsp, 0, {&rvc_fp_rs2, &rvc_sdsp_address}); } - if (isa->extension_enabled(EXT_ZCF) && isa->extension_enabled('F')) { + if (ext_enabled(EXT_ZCF)) { DISASM_INSN("c.flw", c_flw, 0, {&rvc_fp_rs2s, &rvc_lw_address}); DISASM_INSN("c.flwsp", c_flwsp, 0, {&frd, &rvc_lwsp_address}); DISASM_INSN("c.fsw", c_fsw, 0, {&rvc_fp_rs2s, &rvc_lw_address}); DISASM_INSN("c.fswsp", c_fswsp, 0, {&rvc_fp_rs2, &rvc_swsp_address}); } - if (isa->extension_enabled(EXT_ZCB)) { + if (ext_enabled(EXT_ZCB)) { DISASM_INSN("c.zext.b", c_zext_b, 0, {&rvc_rs1s}); DISASM_INSN("c.sext.b", c_sext_b, 0, {&rvc_rs1s}); DISASM_INSN("c.zext.h", c_zext_h, 0, {&rvc_rs1s}); DISASM_INSN("c.sext.h", c_sext_h, 0, {&rvc_rs1s}); - if (isa->get_max_xlen() == 64) { + if (xlen_eq(64)) { DISASM_INSN("c.zext.w", c_zext_w, 0, {&rvc_rs1s}); } DISASM_INSN("c.not", c_not, 0, {&rvc_rs1s}); @@ -1536,8 +1508,8 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("c.sh", c_sh, 0, {&rvc_rs2s, &rvb_h_address}); } - if (isa->extension_enabled(EXT_ZCMP)) { - if (isa->get_max_xlen() == 32) { + if (ext_enabled(EXT_ZCMP)) { + if (xlen_eq_strict(32)) { DISASM_INSN("cm.push", cm_push, 0, {&rvcm_pushpop_rlist, &rvcm_push_stack_adj_32}); DISASM_INSN("cm.pop", cm_pop, 0, {&rvcm_pushpop_rlist, &rvcm_pop_stack_adj_32}); DISASM_INSN("cm.popret", cm_popret, 0, {&rvcm_pushpop_rlist, &rvcm_pop_stack_adj_32}); @@ -1553,12 +1525,12 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("cm.mvsa01", cm_mvsa01, 0, {&rvc_r1s, &rvc_r2s}); } - if (isa->extension_enabled(EXT_ZCMT)) { + if (ext_enabled(EXT_ZCMT)) { DISASM_INSN("cm.jt", cm_jalt, 0x380, {&rvcm_jt_index}); DISASM_INSN("cm.jalt", cm_jalt, 0, {&rvcm_jt_index}); } - if (isa->has_any_vector()) { + if (isa->has_any_vector() || !strict) { DISASM_INSN("vsetivli", vsetivli, 0, {&xrd, &zimm5, &v_vtype}); DISASM_INSN("vsetvli", vsetvli, 0, {&xrd, &xrs1, &v_vtype}); DEFINE_RTYPE(vsetvl); @@ -1642,8 +1614,11 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #define DEFINE_VECTOR_V(code) add_vector_v_insn(this, #code, match_##code, mask_##code) #define DEFINE_VECTOR_VV(code) add_vector_vv_insn(this, #code, match_##code, mask_##code) + #define DEFINE_VECTOR_MULTIPLYADD_VV(code) add_vector_multiplyadd_vv_insn(this, #code, match_##code, mask_##code) #define DEFINE_VECTOR_VX(code) add_vector_vx_insn(this, #code, match_##code, mask_##code) + #define DEFINE_VECTOR_MULTIPLYADD_VX(code) add_vector_multiplyadd_vx_insn(this, #code, match_##code, mask_##code) #define DEFINE_VECTOR_VF(code) add_vector_vf_insn(this, #code, match_##code, mask_##code) + #define DEFINE_VECTOR_MULTIPLYADD_VF(code) add_vector_multiplyadd_vf_insn(this, #code, match_##code, mask_##code) #define DEFINE_VECTOR_VI(code) add_vector_vi_insn(this, #code, match_##code, mask_##code) #define DEFINE_VECTOR_VIU(code) add_vector_viu_insn(this, #code, match_##code, mask_##code) @@ -1659,6 +1634,10 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_VECTOR_VV(name##_vv); \ DEFINE_VECTOR_VX(name##_vx) + #define DISASM_OPIV_MULTIPLYADD_VX__INSN(name, sign) \ + DEFINE_VECTOR_MULTIPLYADD_VV(name##_vv); \ + DEFINE_VECTOR_MULTIPLYADD_VX(name##_vx) + #define DISASM_OPIV__XI_INSN(name, sign) \ DEFINE_VECTOR_VX(name##_vx); \ if (sign) \ @@ -1678,6 +1657,8 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #define DISASM_OPIV__X__INSN(name, sign) DEFINE_VECTOR_VX(name##_vx) + #define DISASM_OPIV_MULTIPLYADD__X__INSN(name, sign) DEFINE_VECTOR_MULTIPLYADD_VX(name##_vx) + #define DEFINE_VECTOR_VVM(name) \ add_vector_vvm_insn(this, #name, match_##name, mask_##name | mask_vm) @@ -1821,10 +1802,10 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_OPIV_VX__INSN(vmul, 1); DISASM_OPIV_VX__INSN(vmulhsu, 0); DISASM_OPIV_VX__INSN(vmulh, 1); - DISASM_OPIV_VX__INSN(vmadd, 1); - DISASM_OPIV_VX__INSN(vnmsub, 1); - DISASM_OPIV_VX__INSN(vmacc, 1); - DISASM_OPIV_VX__INSN(vnmsac, 1); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vmadd, 1); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vnmsub, 1); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vmacc, 1); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vnmsac, 1); //0b11_0000 DISASM_OPIV_VX__INSN(vwaddu, 0); @@ -1838,10 +1819,17 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_OPIV_VX__INSN(vwmulu, 0); DISASM_OPIV_VX__INSN(vwmulsu, 0); DISASM_OPIV_VX__INSN(vwmul, 1); - DISASM_OPIV_VX__INSN(vwmaccu, 0); - DISASM_OPIV_VX__INSN(vwmacc, 1); - DISASM_OPIV__X__INSN(vwmaccus, 1); - DISASM_OPIV_VX__INSN(vwmaccsu, 0); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vwmaccu, 0); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vwmacc, 1); + DISASM_OPIV_MULTIPLYADD__X__INSN(vwmaccus, 1); + DISASM_OPIV_MULTIPLYADD_VX__INSN(vwmaccsu, 0); + + if (ext_enabled(EXT_ZVQDOTQ)) { + DISASM_OPIV_VX__INSN(vqdot, 0); + DISASM_OPIV_VX__INSN(vqdotu, 0); + DISASM_OPIV_VX__INSN(vqdotsu, 0); + DISASM_OPIV__X__INSN(vqdotus, 0); + } #undef DISASM_OPIV_VXI_INSN #undef DISASM_OPIV_VX__INSN @@ -1858,6 +1846,10 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_VECTOR_VV(name##_vv); \ DEFINE_VECTOR_VF(name##_vf) + #define DISASM_OPIV_MULTIPLYADD_VF_INSN(name) \ + DEFINE_VECTOR_MULTIPLYADD_VV(name##_vv); \ + DEFINE_VECTOR_MULTIPLYADD_VF(name##_vf) + #define DISASM_OPIV_WF_INSN(name) \ DEFINE_VECTOR_VV(name##_wv); \ DEFINE_VECTOR_VF(name##_wf) @@ -1925,14 +1917,14 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_OPIV_VF_INSN(vfmul); DISASM_OPIV__F_INSN(vfrsub); - DISASM_OPIV_VF_INSN(vfmadd); - DISASM_OPIV_VF_INSN(vfnmadd); - DISASM_OPIV_VF_INSN(vfmsub); - DISASM_OPIV_VF_INSN(vfnmsub); - DISASM_OPIV_VF_INSN(vfmacc); - DISASM_OPIV_VF_INSN(vfnmacc); - DISASM_OPIV_VF_INSN(vfmsac); - DISASM_OPIV_VF_INSN(vfnmsac); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfmadd); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfnmadd); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfmsub); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfnmsub); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfmacc); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfnmacc); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfmsac); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfnmsac); //0b11_0000 DISASM_OPIV_VF_INSN(vfwadd); @@ -1942,10 +1934,10 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_OPIV_WF_INSN(vfwadd); DISASM_OPIV_WF_INSN(vfwsub); DISASM_OPIV_VF_INSN(vfwmul); - DISASM_OPIV_VF_INSN(vfwmacc); - DISASM_OPIV_VF_INSN(vfwnmacc); - DISASM_OPIV_VF_INSN(vfwmsac); - DISASM_OPIV_VF_INSN(vfwnmsac); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfwmacc); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfwnmacc); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfwmsac); + DISASM_OPIV_MULTIPLYADD_VF_INSN(vfwnmsac); #undef DISASM_OPIV_VF_INSN #undef DISASM_OPIV__F_INSN @@ -1954,40 +1946,42 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #undef DISASM_VFUNARY0_INSN } - if (isa->extension_enabled(EXT_ZVFBFMIN)) { + if (ext_enabled(EXT_ZVFBFMIN)) { DEFINE_VECTOR_V(vfncvtbf16_f_f_w); DEFINE_VECTOR_V(vfwcvtbf16_f_f_v); } - if (isa->extension_enabled(EXT_ZVFBFWMA)) { + if (ext_enabled(EXT_ZVFBFWMA)) { DEFINE_VECTOR_VV(vfwmaccbf16_vv); DEFINE_VECTOR_VF(vfwmaccbf16_vf); } - - if (isa->extension_enabled(EXT_ZMMUL)) { + + if (ext_enabled(EXT_ZMMUL)) { DEFINE_RTYPE(mul); DEFINE_RTYPE(mulh); DEFINE_RTYPE(mulhu); DEFINE_RTYPE(mulhsu); - DEFINE_RTYPE(mulw); + + if (xlen_eq(64)) + DEFINE_RTYPE(mulw); } - if (isa->extension_enabled(EXT_ZICBOM)) { + if (ext_enabled(EXT_ZICBOM)) { DISASM_INSN("cbo.clean", cbo_clean, 0, {&base_only_address}); DISASM_INSN("cbo.flush", cbo_flush, 0, {&base_only_address}); DISASM_INSN("cbo.inval", cbo_inval, 0, {&base_only_address}); } - if (isa->extension_enabled(EXT_ZICBOZ)) { + if (ext_enabled(EXT_ZICBOZ)) { DISASM_INSN("cbo.zero", cbo_zero, 0, {&base_only_address}); } - if (isa->extension_enabled(EXT_ZICOND)) { + if (ext_enabled(EXT_ZICOND)) { DEFINE_RTYPE(czero_eqz); DEFINE_RTYPE(czero_nez); } - if (isa->extension_enabled(EXT_ZIMOP)) { + if (ext_enabled(EXT_ZIMOP)) { #define DISASM_MOP_R(name, rs1, rd) \ add_insn(new disasm_insn_t(#name, match_##name | (rs1 << 15) | (rd << 7), \ 0xFFFFFFFF, {&xrd, &xrs1})); @@ -2023,7 +2017,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_R1TYPE(mop_r_25); DEFINE_R1TYPE(mop_r_26); DEFINE_R1TYPE(mop_r_27); - if (!isa->extension_enabled(EXT_ZICFISS)) { + if (!ext_enabled_strict(EXT_ZICFISS)) { DEFINE_R1TYPE(mop_r_28); } else { // Add code points of mop_r_28 not used by Zicfiss @@ -2043,7 +2037,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_RTYPE(mop_rr_5); DEFINE_RTYPE(mop_rr_6); DEFINE_RTYPE(mop_rr_7); - if (!isa->extension_enabled(EXT_ZICFISS)) { + if (!ext_enabled_strict(EXT_ZICFISS)) { DEFINE_RTYPE(mop_rr_7); } else { // Add code points of mop_rr_7 not used by Zicfiss @@ -2055,11 +2049,11 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } } - if (isa->extension_enabled(EXT_ZCMOP)) { - if (!isa->extension_enabled(EXT_ZICFISS)) + if (ext_enabled(EXT_ZCMOP)) { + if (!ext_enabled_strict(EXT_ZICFISS)) DISASM_INSN("c.mop.1", c_mop_1, 0, {}); DISASM_INSN("c.mop.3", c_mop_3, 0, {}); - if (!isa->extension_enabled(EXT_ZICFISS)) + if (!ext_enabled_strict(EXT_ZICFISS)) DISASM_INSN("c.mop.5", c_mop_5, 0, {}); DISASM_INSN("c.mop.7", c_mop_7, 0, {}); DISASM_INSN("c.mop.9", c_mop_9, 0, {}); @@ -2068,44 +2062,50 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("c.mop.15", c_mop_15, 0, {}); } - if (isa->extension_enabled(EXT_ZKND) || - isa->extension_enabled(EXT_ZKNE)) { + if (ext_enabled(EXT_ZKND) || ext_enabled(EXT_ZKNE)) { DISASM_INSN("aes64ks1i", aes64ks1i, 0, {&xrd, &xrs1, &rcon}); DEFINE_RTYPE(aes64ks2); } - if (isa->extension_enabled(EXT_ZKND)) { - if(isa->get_max_xlen() == 64) { + if (ext_enabled(EXT_ZKND)) { + if (xlen_eq(64)) { DEFINE_RTYPE(aes64ds); DEFINE_RTYPE(aes64dsm); DEFINE_R1TYPE(aes64im); - } else if (isa->get_max_xlen() == 32) { + } + + if (xlen_eq(32)) { DISASM_INSN("aes32dsi", aes32dsi, 0, {&xrd, &xrs1, &xrs2, &bs}); DISASM_INSN("aes32dsmi", aes32dsmi, 0, {&xrd, &xrs1, &xrs2, &bs}); } } - if (isa->extension_enabled(EXT_ZKNE)) { - if(isa->get_max_xlen() == 64) { + if (ext_enabled(EXT_ZKNE)) { + if (xlen_eq(64)) { DEFINE_RTYPE(aes64es); DEFINE_RTYPE(aes64esm); - } else if (isa->get_max_xlen() == 32) { + } + + if (xlen_eq(32)) { DISASM_INSN("aes32esi", aes32esi, 0, {&xrd, &xrs1, &xrs2, &bs}); DISASM_INSN("aes32esmi", aes32esmi, 0, {&xrd, &xrs1, &xrs2, &bs}); } } - if (isa->extension_enabled(EXT_ZKNH)) { + if (ext_enabled(EXT_ZKNH)) { DEFINE_R1TYPE(sha256sig0); DEFINE_R1TYPE(sha256sig1); DEFINE_R1TYPE(sha256sum0); DEFINE_R1TYPE(sha256sum1); - if(isa->get_max_xlen() == 64) { + + if (xlen_eq(64)) { DEFINE_R1TYPE(sha512sig0); DEFINE_R1TYPE(sha512sig1); DEFINE_R1TYPE(sha512sum0); DEFINE_R1TYPE(sha512sum1); - } else if (isa->get_max_xlen() == 32) { + } + + if (xlen_eq(32)) { DEFINE_RTYPE(sha512sig0h); DEFINE_RTYPE(sha512sig0l); DEFINE_RTYPE(sha512sig1h); @@ -2115,17 +2115,17 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } } - if (isa->extension_enabled(EXT_ZKSED)) { + if (ext_enabled(EXT_ZKSED)) { DISASM_INSN("sm4ed", sm4ed, 0, {&xrd, &xrs1, &xrs2, &bs}); DISASM_INSN("sm4ks", sm4ks, 0, {&xrd, &xrs1, &xrs2, &bs}); } - if (isa->extension_enabled(EXT_ZKSH)) { + if (ext_enabled(EXT_ZKSH)) { DEFINE_R1TYPE(sm3p0); DEFINE_R1TYPE(sm3p1); } - if (isa->extension_enabled(EXT_ZVBB)) { + if (ext_enabled(EXT_ZVBB)) { #define DEFINE_VECTOR_VIU_ZIMM6(code) \ add_vector_viu_z6_insn(this, #code, match_##code, mask_##code) #define DISASM_VECTOR_VV_VX(name) \ @@ -2157,7 +2157,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #undef DISASM_VECTOR_VV_VX_VIU_ZIMM6 } - if (isa->extension_enabled(EXT_ZVBC)) { + if (ext_enabled(EXT_ZVBC)) { #define DISASM_VECTOR_VV_VX(name) \ DEFINE_VECTOR_VV(name##_vv); \ DEFINE_VECTOR_VX(name##_vx) @@ -2168,14 +2168,14 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #undef DISASM_VECTOR_VV_VX } - if (isa->extension_enabled(EXT_ZVKG)) { + if (ext_enabled(EXT_ZVKG)) { // Despite its suffix, the vgmul.vv instruction // is really ".v", with the form "vgmul.vv vd, vs2". DEFINE_VECTOR_V(vgmul_vv); DEFINE_VECTOR_VV(vghsh_vv); } - if (isa->extension_enabled(EXT_ZVKNED)) { + if (ext_enabled(EXT_ZVKNED)) { // Despite their suffixes, the vaes*.{vv,vs} instructions // are really ".v", with the form "<op>.{vv,vs} vd, vs2". #define DISASM_VECTOR_VV_VS(name) \ @@ -2193,14 +2193,13 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) #undef DISASM_VECTOR_VV_VS } - if (isa->extension_enabled(EXT_ZVKNHA) || - isa->extension_enabled(EXT_ZVKNHB)) { + if (ext_enabled(EXT_ZVKNHA) || ext_enabled(EXT_ZVKNHB)) { DEFINE_VECTOR_VV(vsha2ms_vv); DEFINE_VECTOR_VV(vsha2ch_vv); DEFINE_VECTOR_VV(vsha2cl_vv); } - if (isa->extension_enabled(EXT_ZVKSED)) { + if (ext_enabled(EXT_ZVKSED)) { DEFINE_VECTOR_VIU(vsm4k_vi); // Despite their suffixes, the vsm4r.{vv,vs} instructions // are really ".v", with the form "vsm4r.{vv,vs} vd, vs2". @@ -2208,12 +2207,12 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_VECTOR_V(vsm4r_vs); } - if (isa->extension_enabled(EXT_ZVKSH)) { + if (ext_enabled(EXT_ZVKSH)) { DEFINE_VECTOR_VIU(vsm3c_vi); DEFINE_VECTOR_VV(vsm3me_vv); } - if (isa->extension_enabled(EXT_ZALASR)) { + if (ext_enabled(EXT_ZALASR)) { DEFINE_XLOAD_BASE(lb_aq); DEFINE_XLOAD_BASE(lh_aq); DEFINE_XLOAD_BASE(lw_aq); @@ -2224,7 +2223,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_XSTORE_BASE(sd_rl); } - if(isa->extension_enabled(EXT_ZICFISS)) { + if (ext_enabled(EXT_ZICFISS)) { DISASM_INSN("sspush", sspush_x1, 0, {&xrs2}); DISASM_INSN("sspush", sspush_x5, 0, {&xrs2}); DISASM_INSN("sspopchk", sspopchk_x1, 0, {&xrs1}); @@ -2232,30 +2231,28 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DISASM_INSN("ssrdp", ssrdp, 0, {&xrd}); DEFINE_XAMO(ssamoswap_w); - if(isa->get_max_xlen() == 64) + if (xlen_eq(64)) DEFINE_XAMO(ssamoswap_d) - if (isa->extension_enabled(EXT_ZCA)) { + if (ext_enabled(EXT_ZCA)) { DISASM_INSN("c.sspush", c_sspush_x1, 0, {&rvc_ra}); DISASM_INSN("c.sspopchk", c_sspopchk_x5, 0, {&rvc_t0}); } } } -disassembler_t::disassembler_t(const isa_parser_t *isa) +disassembler_t::disassembler_t(const isa_parser_t *isa, bool strict) { // highest priority: instructions explicitly enabled - add_instructions(isa); + add_instructions(isa, true); - // next-highest priority: other instructions in same base ISA - std::string fallback_isa_string = std::string("rv") + std::to_string(isa->get_max_xlen()) + - "gqcvh_zfh_zfa_zba_zbb_zbc_zbs_zcb_zicbom_zicboz_zicond_zk_zks_svinval_" - "zcmop_zimop_zawrs_zicfiss_zicfilp_zvknc_zvkg_zvfbfmin_zvfbfwma_zfbfmin"; - isa_parser_t fallback_isa(fallback_isa_string.c_str(), DEFAULT_PRIV); - add_instructions(&fallback_isa); + if (!strict) { + // next-highest priority: other instructions in same base ISA + add_instructions(isa, false); - // finally: instructions with known opcodes but unknown arguments - add_unknown_insns(this); + // finally: instructions with known opcodes but unknown arguments + add_unknown_insns(this); + } // Now, reverse the lists, because we search them back-to-front (so that // custom instructions later added with add_insn have highest priority). diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index e37b72f..24eb5f2 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -1,14 +1,35 @@ #include "isa_parser.h" +#include <cstring> #include <stdexcept> static std::string strtolower(const char* str) { - std::string res; - for (const char *r = str; *r; r++) - res += std::tolower(*r); + std::string res(str); + for (char &c : res) + c = std::tolower(c); return res; } +static unsigned long safe_stoul(const std::string& s) +{ + int old_errno = errno; + errno = 0; + + char* endp; + unsigned long ret = strtoul(s.c_str(), &endp, 10); + + int new_errno = errno; + errno = old_errno; + + if (endp == s.c_str() || *endp) + throw std::invalid_argument("stoul"); + + if (new_errno) + throw std::out_of_range("stoul"); + + return ret; +} + static void bad_option_string(const char *option, const char *value, const char *msg) { @@ -30,7 +51,7 @@ static void bad_priv_string(const char* priv) isa_parser_t::isa_parser_t(const char* str, const char *priv) { isa_string = strtolower(str); - const char* all_subsets = "mafdqcpvhb"; + const char* all_subsets = "mafdqcbpvh"; if (isa_string.compare(0, 4, "rv32") == 0) max_xlen = 32; @@ -49,7 +70,7 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) // G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two // unconditionally, so they need not be explicitly added here. isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5); - // Fall through + [[fallthrough]]; case 'i': extension_table['I'] = true; break; @@ -77,9 +98,9 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) switch (*p) { case 'v': vlen = 128; elen = 64; zvf = true; zvd = true; - // even rv32iv implies double float + [[fallthrough]]; case 'q': extension_table['D'] = true; - // Fall through + [[fallthrough]]; case 'd': extension_table['F'] = true; } extension_table[toupper(*p)] = true; @@ -119,6 +140,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) // HINTs encoded in base-ISA instructions are always present. } else if (ext_str == "zihintntl") { // HINTs encoded in base-ISA instructions are always present. + } else if (ext_str == "ziccid") { + extension_table[EXT_ZICCID] = true; + } else if (ext_str == "ziccif") { + // aligned instruction fetch is always atomic in Spike } else if (ext_str == "zaamo") { extension_table[EXT_ZAAMO] = true; } else if (ext_str == "zalrsc") { @@ -224,6 +249,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_SSCOFPMF] = true; } else if (ext_str == "svadu") { extension_table[EXT_SVADU] = true; + } else if (ext_str == "svade") { + extension_table[EXT_SVADE] = true; } else if (ext_str == "svnapot") { extension_table[EXT_SVNAPOT] = true; } else if (ext_str == "svpbmt") { @@ -247,8 +274,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) if (max_xlen != 32) bad_isa_string(str, "'Zilsd' requires RV32"); extension_table[EXT_ZILSD] = true; - } else if (ext_str == "zcmlsd") { - extension_table[EXT_ZCMLSD] = true; + } else if (ext_str == "zclsd") { + extension_table[EXT_ZCLSD] = true; } else if (ext_str == "zvbb") { extension_table[EXT_ZVBB] = true; } else if (ext_str == "zvbc") { @@ -297,6 +324,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_ZVKSED] = true; } else if (ext_str == "zvksh") { extension_table[EXT_ZVKSH] = true; + } else if (ext_str == "zvqdotq") { + extension_table[EXT_ZVQDOTQ] = true; } else if (ext_str == "zvkt") { } else if (ext_str == "sstc") { extension_table[EXT_SSTC] = true; @@ -306,6 +335,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_SSCSRIND] = true; } else if (ext_str == "smcntrpmf") { extension_table[EXT_SMCNTRPMF] = true; + } else if (ext_str == "smcdeleg") { + extension_table[EXT_SMCDELEG] = true; + } else if (ext_str == "ssccfg") { + extension_table[EXT_SSCCFG] = true; } else if (ext_str == "zimop") { extension_table[EXT_ZIMOP] = true; } else if (ext_str == "zcmop") { @@ -318,20 +351,26 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_ZICFILP] = true; } else if (ext_str == "zicfiss") { extension_table[EXT_ZICFISS] = true; + } else if (ext_str == "smmpm") { + extension_table[EXT_SMMPM] = true; + } else if (ext_str == "smnpm") { + extension_table[EXT_SMNPM] = true; + } else if (ext_str == "ssnpm") { + extension_table[EXT_SSNPM] = true; } else if (ext_str.substr(0, 3) == "zvl") { reg_t new_vlen; try { - new_vlen = std::stol(ext_str.substr(3, ext_str.size() - 4)); + new_vlen = safe_stoul(ext_str.substr(3, ext_str.size() - 4)); } catch (std::logic_error& e) { new_vlen = 0; } - if ((new_vlen & (new_vlen - 1)) != 0 || new_vlen < 32) + if ((new_vlen & (new_vlen - 1)) != 0 || new_vlen < 32 || ext_str.back() != 'b') bad_isa_string(str, ("Invalid Zvl string: " + ext_str).c_str()); vlen = std::max(vlen, new_vlen); } else if (ext_str.substr(0, 3) == "zve") { reg_t new_elen; try { - new_elen = std::stol(ext_str.substr(3, ext_str.size() - 4)); + new_elen = safe_stoul(ext_str.substr(3, ext_str.size() - 4)); } catch (std::logic_error& e) { new_elen = 0; } @@ -347,6 +386,18 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) if (new_elen != 32 && new_elen != 64) bad_isa_string(str, ("Invalid Zve string: " + ext_str).c_str()); elen = std::max(elen, new_elen); + } else if (ext_str == "ssdbltrp") { + extension_table[EXT_SSDBLTRP] = true; + } else if (ext_str == "smdbltrp") { + extension_table[EXT_SMDBLTRP] = true; + } else if (ext_str == "smaia") { + extension_table[EXT_SMAIA] = true; + extension_table[EXT_SSAIA] = true; + extension_table[EXT_SMCSRIND] = true; + extension_table[EXT_SSCSRIND] = true; + } else if (ext_str == "ssaia") { + extension_table[EXT_SSAIA] = true; + extension_table[EXT_SSCSRIND] = true; } else if (ext_str[0] == 'x') { extension_table['X'] = true; if (ext_str.size() == 1) { @@ -386,12 +437,12 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_ZCD] = true; } - if (extension_table[EXT_ZCMLSD] && extension_table[EXT_ZCF]) { - bad_isa_string(str, "'Zcmlsd' extension conflicts with 'Zcf' extensions"); + if (extension_table[EXT_ZCLSD] && extension_table[EXT_ZCF]) { + bad_isa_string(str, "'Zclsd' extension conflicts with 'Zcf' extensions"); } - if (extension_table[EXT_ZCMLSD] && (!extension_table[EXT_ZCA] || !extension_table[EXT_ZILSD])) { - bad_isa_string(str, "'Zcmlsd' extension requires 'Zca' and 'Zilsd' extensions"); + if (extension_table[EXT_ZCLSD] && (!extension_table[EXT_ZCA] || !extension_table[EXT_ZILSD])) { + bad_isa_string(str, "'Zclsd' extension requires 'Zca' and 'Zilsd' extensions"); } if (extension_table[EXT_ZFBFMIN] && !extension_table['F']) { diff --git a/fdt/fdt.mk.in b/fdt/fdt.mk.in index 64d06ac..accc080 100644 --- a/fdt/fdt.mk.in +++ b/fdt/fdt.mk.in @@ -16,4 +16,4 @@ fdt_c_srcs = \ fdt_addresses.c \ fdt_overlay.c \ -fdt_CFLAGS = -I$(src_dir)/fdt +fdt_CFLAGS = -I$(src_dir)/fdt -Wno-sign-compare diff --git a/fdt/libfdt.h b/fdt/libfdt.h index d2356cc..8fb42fb 100644 --- a/fdt/libfdt.h +++ b/fdt/libfdt.h @@ -6,8 +6,8 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. */ -#include <libfdt_env.h> -#include <fdt.h> +#include "libfdt_env.h" +#include "fdt.h" #define FDT_FIRST_SUPPORTED_VERSION 0x02 #define FDT_LAST_SUPPORTED_VERSION 0x11 diff --git a/fesvr/byteorder.h b/fesvr/byteorder.h index d9e503a..2147f96 100644 --- a/fesvr/byteorder.h +++ b/fesvr/byteorder.h @@ -3,8 +3,8 @@ #ifndef _RISCV_BYTEORDER_H #define _RISCV_BYTEORDER_H -#include "config.h" #include <stdint.h> +#include <arpa/inet.h> static inline uint8_t swap(uint8_t n) { return n; } static inline uint16_t swap(uint16_t n) { return (n >> 8) | (n << 8); } @@ -16,23 +16,17 @@ static inline int32_t swap(int32_t n) { return int32_t(swap(uint32_t(n))); } static inline int64_t swap(int64_t n) { return int64_t(swap(uint64_t(n))); } #ifdef HAVE_INT128 -typedef __int128 int128_t; -typedef unsigned __int128 uint128_t; +__extension__ typedef __int128 int128_t; +__extension__ typedef unsigned __int128 uint128_t; static inline uint128_t swap(uint128_t n) { return (uint128_t(swap(uint64_t(n))) << 64) | swap(uint64_t(n >> 64)); } static inline int128_t swap(int128_t n) { return int128_t(swap(uint128_t(n))); } #endif -#ifdef WORDS_BIGENDIAN -template<typename T> static inline T from_be(T n) { return n; } -template<typename T> static inline T to_be(T n) { return n; } -template<typename T> static inline T from_le(T n) { return swap(n); } -template<typename T> static inline T to_le(T n) { return swap(n); } -#else -template<typename T> static inline T from_le(T n) { return n; } -template<typename T> static inline T to_le(T n) { return n; } -template<typename T> static inline T from_be(T n) { return swap(n); } -template<typename T> static inline T to_be(T n) { return swap(n); } -#endif +static inline bool is_be() { return htonl(1) == 1; } +template<typename T> static inline T from_be(T n) { return is_be() ? n : swap(n); } +template<typename T> static inline T to_be(T n) { return from_be(n); } +template<typename T> static inline T from_le(T n) { return is_be() ? swap(n) : n; } +template<typename T> static inline T to_le(T n) { return from_le(n); } // Wrapper to mark a value as target endian, to guide conversion code diff --git a/fesvr/dtm.cc b/fesvr/dtm.cc index 0f810e7..a0c3254 100644 --- a/fesvr/dtm.cc +++ b/fesvr/dtm.cc @@ -51,6 +51,9 @@ } \ } +#define MAX_DATA_WORDS (1 << DM_ABSTRACTCS_DATACOUNT_LENGTH) +#define MAX_PROG_WORDS (1 << DM_ABSTRACTCS_PROGBUFSIZE_LENGTH) + uint32_t dtm_t::do_command(dtm_t::req r) { req_buf = r; @@ -61,17 +64,20 @@ uint32_t dtm_t::do_command(dtm_t::req r) uint32_t dtm_t::read(uint32_t addr) { - return do_command((req){addr, 1, 0}); + req r = {addr, 1, 0}; + return do_command(r); } uint32_t dtm_t::write(uint32_t addr, uint32_t data) { - return do_command((req){addr, 2, data}); + req r = {addr, 2, data}; + return do_command(r); } void dtm_t::nop() { - do_command((req){0, 0, 0}); + req r = {0, 0, 0}; + do_command(r); } void dtm_t::select_hart(int hartsel) { @@ -104,7 +110,7 @@ void dtm_t::halt(int hartsel) read(DM_DMSTATUS); } - int dmcontrol = DM_DMCONTROL_HALTREQ | DM_DMCONTROL_DMACTIVE; + reg_t dmcontrol = DM_DMCONTROL_HALTREQ | DM_DMCONTROL_DMACTIVE; dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, hartsel); write(DM_DMCONTROL, dmcontrol); int dmstatus; @@ -142,7 +148,7 @@ void dtm_t::resume(int hartsel) uint64_t dtm_t::save_reg(unsigned regno) { - uint32_t data[xlen/(8*4)]; + uint32_t data[MAX_DATA_WORDS]; uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno); RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4)); @@ -155,7 +161,7 @@ uint64_t dtm_t::save_reg(unsigned regno) void dtm_t::restore_reg(unsigned regno, uint64_t val) { - uint32_t data[xlen/(8*4)]; + uint32_t data[MAX_DATA_WORDS]; data[0] = (uint32_t) val; if (xlen > 32) { data[1] = (uint32_t) (val >> 32); @@ -174,8 +180,8 @@ uint32_t dtm_t::run_abstract_command(uint32_t command, const uint32_t program[], size_t program_n, uint32_t data[], size_t data_n) { - assert(program_n <= ram_words); - assert(data_n <= data_words); + assert(program_n <= MAX_PROG_WORDS); + assert(data_n <= MAX_DATA_WORDS); for (size_t i = 0; i < program_n; i++) { write(DM_PROGBUF0 + i, program[i]); @@ -214,8 +220,8 @@ size_t dtm_t::chunk_align() void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; uint8_t * curr = (uint8_t*) dst; @@ -267,8 +273,8 @@ void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst) void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; const uint8_t * curr = (const uint8_t*) src; @@ -362,8 +368,8 @@ void dtm_t::die(uint32_t cmderr) void dtm_t::clear_chunk(uint64_t taddr, size_t len) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; halt(current_hart); uint64_t s0 = save_reg(S0); @@ -477,8 +483,8 @@ uint32_t dtm_t::get_xlen() uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0); uint32_t cmderr; - const uint32_t prog[] = {}; - uint32_t data[] = {}; + const uint32_t prog[1] = {}; + uint32_t data[1] = {}; cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0); if (cmderr == 0){ @@ -560,11 +566,6 @@ void dtm_t::producer_thread() // Poll until the debugger agrees it's enabled. while ((read(DM_DMCONTROL) & DM_DMCONTROL_DMACTIVE) == 0) ; - // These are checked every time we run an abstract command. - uint32_t abstractcs = read(DM_ABSTRACTCS); - ram_words = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); - data_words = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); - // These things are only needed for the 'modify_csr' function. // That could be re-written to not use these at some performance // overhead. diff --git a/fesvr/dtm.h b/fesvr/dtm.h index f47b648..03c2f79 100644 --- a/fesvr/dtm.h +++ b/fesvr/dtm.h @@ -109,8 +109,6 @@ class dtm_t : public htif_t static const int max_idle_cycles = 10000; - size_t ram_words; - size_t data_words; int num_harts; int current_hart; diff --git a/fesvr/elfloader.h b/fesvr/elfloader.h index 0a250cd..6cbdda3 100644 --- a/fesvr/elfloader.h +++ b/fesvr/elfloader.h @@ -4,6 +4,7 @@ #define _ELFLOADER_H #include "elf.h" +#include "memif.h" #include <map> #include <string> diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 46f15d3..15f79bf 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -46,7 +46,7 @@ static void handle_signal(int sig) htif_t::htif_t() : mem(this), entry(DRAM_BASE), sig_addr(0), sig_len(0), - tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false), + tohost_addr(0), fromhost_addr(0), stopped(false), syscall_proxy(this) { signal(SIGINT, &handle_signal); @@ -65,14 +65,14 @@ htif_t::htif_t(int argc, char** argv) : htif_t() htif_t::htif_t(const std::vector<std::string>& args) : htif_t() { int argc = args.size() + 1; - char * argv[argc]; + std::vector<char*>argv(argc); argv[0] = (char *) "htif"; for (unsigned int i = 0; i < args.size(); i++) { argv[i+1] = (char *) args[i].c_str(); } //Set line size as 16 by default. line_size = 16; - parse_arguments(argc, argv); + parse_arguments(argc, &argv[0]); register_devices(); } @@ -84,16 +84,20 @@ htif_t::~htif_t() void htif_t::start() { - if (!targs.empty() && targs[0] != "none") { - try { - load_program(); - } catch (const incompat_xlen & err) { - fprintf(stderr, "Error: cannot execute %d-bit program on RV%d hart\n", err.actual_xlen, err.expected_xlen); - exit(1); + if (!targs.empty()) { + if (targs[0] != "none") { + try { + load_program(); + } catch (const incompat_xlen & err) { + fprintf(stderr, "Error: cannot execute %d-bit program on RV%d hart\n", err.actual_xlen, err.expected_xlen); + exit(1); + } + reset(); + } else { + auto empty_symbols = std::map<std::string, uint64_t>(); + load_symbols(empty_symbols); } } - - reset(); } static void bad_address(const std::string& situation, reg_t addr) @@ -116,7 +120,7 @@ std::map<std::string, uint64_t> htif_t::load_payload(const std::string& payload, else throw std::runtime_error( "could not open " + payload + "; searched paths:\n" + - "\t. (current directory)\n" + + "\t. (current directory)\n" + "\t" + PREFIX TARGET_DIR + " (based on configured --prefix and --with-target)" ); } @@ -150,35 +154,13 @@ std::map<std::string, uint64_t> htif_t::load_payload(const std::string& payload, } } -void htif_t::load_program() +void htif_t::load_symbols(std::map<std::string, uint64_t>& symbols) { - std::map<std::string, uint64_t> symbols = load_payload(targs[0], &entry, load_offset); - - if (symbols.count("tohost") && symbols.count("fromhost")) { - tohost_addr = symbols["tohost"]; - fromhost_addr = symbols["fromhost"]; - } else { - fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n"); - } - - // detect torture tests so we can print the memory signature at the end - if (symbols.count("begin_signature") && symbols.count("end_signature")) { - sig_addr = symbols["begin_signature"]; - sig_len = symbols["end_signature"] - sig_addr; - } - - for (auto payload : payloads) { - reg_t dummy_entry; - load_payload(payload, &dummy_entry, 0); - } - class nop_memif_t : public memif_t { public: - nop_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {} + nop_memif_t(htif_t* htif) : memif_t(htif) {} void read(addr_t UNUSED addr, size_t UNUSED len, void UNUSED *bytes) override {} void write(addr_t UNUSED taddr, size_t UNUSED len, const void UNUSED *src) override {} - private: - htif_t* htif; } nop_memif(this); reg_t nop_entry; @@ -188,11 +170,36 @@ void htif_t::load_program() symbols.merge(other_symbols); } + // detect torture tests so we can print the memory signature at the end + if (symbols.count("begin_signature") && symbols.count("end_signature")) { + sig_addr = symbols["begin_signature"]; + sig_len = symbols["end_signature"] - sig_addr; + } + + if (symbols.count("tohost") && symbols.count("fromhost")) { + tohost_addr = symbols["tohost"]; + fromhost_addr = symbols["fromhost"]; + } else { + fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n"); + } + for (auto i : symbols) { auto it = addr2symbol.find(i.second); if ( it == addr2symbol.end()) addr2symbol[i.second] = i.first; } +} + +void htif_t::load_program() +{ + std::map<std::string, uint64_t> symbols = load_payload(targs[0], &entry, load_offset); + + load_symbols(symbols); + + for (auto payload : payloads) { + reg_t dummy_entry; + load_payload(payload, &dummy_entry, 0); + } return; } @@ -207,6 +214,14 @@ const char* htif_t::get_symbol(uint64_t addr) return it->second.c_str(); } +bool htif_t::should_exit() const { + return signal_exit || exitcode.has_value(); +} + +void htif_t::htif_exit(int exit_code) { + exitcode = exit_code; +} + void htif_t::stop() { if (!sig_file.empty() && sig_len) // print final torture test signature @@ -236,11 +251,10 @@ void htif_t::stop() void htif_t::clear_chunk(addr_t taddr, size_t len) { - char zeros[chunk_max_size()]; - memset(zeros, 0, chunk_max_size()); + std::vector<uint8_t> zeros(chunk_max_size(), 0); for (size_t pos = 0; pos < len; pos += chunk_max_size()) - write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), zeros); + write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), &zeros[0]); } int htif_t::run() @@ -253,11 +267,11 @@ int htif_t::run() std::bind(enq_func, &fromhost_queue, std::placeholders::_1); if (tohost_addr == 0) { - while (!signal_exit) + while (!should_exit()) idle(); } - while (!signal_exit && exitcode == 0) + while (!should_exit()) { uint64_t tohost; @@ -305,7 +319,7 @@ bool htif_t::done() int htif_t::exit_code() { - return exitcode >> 1; + return exitcode.value_or(0) >> 1; } void htif_t::parse_arguments(int argc, char ** argv) diff --git a/fesvr/htif.h b/fesvr/htif.h index 74511f5..380e24a 100644 --- a/fesvr/htif.h +++ b/fesvr/htif.h @@ -24,6 +24,9 @@ class htif_t : public chunked_memif_t virtual void start(); virtual void stop(); + // Cause the simulation to exit with the given exit code. + void htif_exit(int exit_code); + int run(); bool done(); int exit_code(); @@ -62,6 +65,7 @@ class htif_t : public chunked_memif_t virtual std::map<std::string, uint64_t> load_payload(const std::string& payload, reg_t* entry, reg_t load_addr); virtual void load_program(); + virtual void load_symbols(std::map<std::string, uint64_t>&); virtual void idle() {} const std::vector<std::string>& host_args() { return hargs; } @@ -76,6 +80,10 @@ class htif_t : public chunked_memif_t // Given an address, return symbol from addr2symbol map const char* get_symbol(uint64_t addr); + // Return true if the simulation should exit due to a signal, + // or end-of-test from HTIF, or an instruction limit. + bool should_exit() const; + private: void parse_arguments(int argc, char ** argv); void register_devices(); @@ -93,7 +101,8 @@ class htif_t : public chunked_memif_t addr_t sig_len; // torture addr_t tohost_addr; addr_t fromhost_addr; - int exitcode; + // Set to a value by htif_exit() when the simulation should exit. + std::optional<int> exitcode; bool stopped; device_list_t device_list; diff --git a/fesvr/htif_pthread.h b/fesvr/htif_pthread.h index c00c382..ab56007 100644 --- a/fesvr/htif_pthread.h +++ b/fesvr/htif_pthread.h @@ -13,7 +13,7 @@ class htif_pthread_t : public htif_t htif_pthread_t(int argc, char** argv); virtual ~htif_pthread_t(); - // target inteface + // target interface void send(const void* buf, size_t size); void recv(void* buf, size_t size); bool recv_nonblocking(void* buf, size_t size); diff --git a/fesvr/memif.cc b/fesvr/memif.cc index e56bd94..59938b9 100644 --- a/fesvr/memif.cc +++ b/fesvr/memif.cc @@ -12,10 +12,10 @@ void memif_t::read(addr_t addr, size_t len, void* bytes) if (len && (addr & (align-1))) { size_t this_len = std::min(len, align - size_t(addr & (align-1))); - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr & ~(align-1), align, chunk); - memcpy(bytes, chunk + (addr & (align-1)), this_len); + cmemif->read_chunk(addr & ~(align-1), align, &chunk[0]); + memcpy(bytes, &chunk[addr & (align-1)], this_len); bytes = (char*)bytes + this_len; addr += this_len; @@ -26,10 +26,10 @@ void memif_t::read(addr_t addr, size_t len, void* bytes) { size_t this_len = len & (align-1); size_t start = len - this_len; - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr + start, align, chunk); - memcpy((char*)bytes + start, chunk, this_len); + cmemif->read_chunk(addr + start, align, &chunk[0]); + memcpy((char*)bytes + start, &chunk[0], this_len); len -= this_len; } @@ -45,11 +45,11 @@ void memif_t::write(addr_t addr, size_t len, const void* bytes) if (len && (addr & (align-1))) { size_t this_len = std::min(len, align - size_t(addr & (align-1))); - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr & ~(align-1), align, chunk); - memcpy(chunk + (addr & (align-1)), bytes, this_len); - cmemif->write_chunk(addr & ~(align-1), align, chunk); + cmemif->read_chunk(addr & ~(align-1), align, &chunk[0]); + memcpy(&chunk[addr & (align-1)], bytes, this_len); + cmemif->write_chunk(addr & ~(align-1), align, &chunk[0]); bytes = (char*)bytes + this_len; addr += this_len; @@ -60,11 +60,11 @@ void memif_t::write(addr_t addr, size_t len, const void* bytes) { size_t this_len = len & (align-1); size_t start = len - this_len; - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr + start, align, chunk); - memcpy(chunk, (char*)bytes + start, this_len); - cmemif->write_chunk(addr + start, align, chunk); + cmemif->read_chunk(addr + start, align, &chunk[0]); + memcpy(&chunk[0], (char*)bytes + start, this_len); + cmemif->write_chunk(addr + start, align, &chunk[0]); len -= this_len; } diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index 162cbfc..014a468 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -114,19 +114,23 @@ struct riscv_statx attributes_mask(htif->to_target<uint64_t>(s.stx_attributes_mask)), atime { htif->to_target<int64_t>(s.stx_atime.tv_sec), - htif->to_target<uint32_t>(s.stx_atime.tv_nsec) + htif->to_target<uint32_t>(s.stx_atime.tv_nsec), + htif->to_target<int32_t>(0) }, btime { htif->to_target<int64_t>(s.stx_btime.tv_sec), - htif->to_target<uint32_t>(s.stx_btime.tv_nsec) + htif->to_target<uint32_t>(s.stx_btime.tv_nsec), + htif->to_target<int32_t>(0) }, ctime { htif->to_target<int64_t>(s.stx_ctime.tv_sec), - htif->to_target<uint32_t>(s.stx_ctime.tv_nsec) + htif->to_target<uint32_t>(s.stx_ctime.tv_nsec), + htif->to_target<int32_t>(0) }, mtime { htif->to_target<int64_t>(s.stx_mtime.tv_sec), - htif->to_target<uint32_t>(s.stx_mtime.tv_nsec) + htif->to_target<uint32_t>(s.stx_mtime.tv_nsec), + htif->to_target<int32_t>(0) }, rdev_major(htif->to_target<uint32_t>(s.stx_rdev_major)), rdev_minor(htif->to_target<uint32_t>(s.stx_rdev_minor)), @@ -137,7 +141,7 @@ struct riscv_statx __spare2(), __spare3() #else __spare2() -#endif +#endif {} }; #endif @@ -221,7 +225,7 @@ void syscall_t::handle_syscall(command_t cmd) reg_t syscall_t::sys_exit(reg_t code, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) { - htif->exitcode = code << 1 | 1; + htif->htif_exit(code << 1 | 1); return 0; } diff --git a/ax_append_flag.m4 b/m4/ax_append_flag.m4 index dd6d8b6..dd6d8b6 100644 --- a/ax_append_flag.m4 +++ b/m4/ax_append_flag.m4 diff --git a/ax_append_link_flags.m4 b/m4/ax_append_link_flags.m4 index 99b9fa5..99b9fa5 100644 --- a/ax_append_link_flags.m4 +++ b/m4/ax_append_link_flags.m4 diff --git a/ax_boost_asio.m4 b/m4/ax_boost_asio.m4 index 4247b33..4247b33 100644 --- a/ax_boost_asio.m4 +++ b/m4/ax_boost_asio.m4 diff --git a/ax_boost_base.m4 b/m4/ax_boost_base.m4 index 519f1c9..9d5a08c 100644 --- a/ax_boost_base.m4 +++ b/m4/ax_boost_base.m4 @@ -10,10 +10,10 @@ # # Test for the Boost C++ libraries of a particular version (or newer) # -# If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt and /opt/local and evaluates the -# $BOOST_ROOT environment variable. Further documentation is available at -# <http://randspringer.de/boost/index.html>. +# If no path to the installed boost library is given the macro searches +# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates +# the $BOOST_ROOT environment variable. Further documentation is available +# at <http://randspringer.de/boost/index.html>. # # This macro calls: # @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 49 +#serial 55 # example boost program (need to pass version) m4_define([_AX_BOOST_BASE_PROGRAM], @@ -114,7 +114,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ AS_CASE([${host_cpu}], [x86_64],[libsubdirs="lib64 libx32 lib lib64"], [mips*64*],[libsubdirs="lib64 lib32 lib lib64"], - [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k],[libsubdirs="lib64 lib lib64"], + [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k|loongarch64],[libsubdirs="lib64 lib lib64"], [libsubdirs="lib"] ) @@ -128,7 +128,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ ) dnl first we check the system location for boost libraries - dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl this location is chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) @@ -151,7 +151,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ else search_libsubdirs="$multiarch_libsubdir $libsubdirs" fi - for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then for libsubdir in $search_libsubdirs ; do if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi @@ -227,7 +227,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ fi else if test "x$cross_compiling" != "xyes" ; then - for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` @@ -289,6 +289,8 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ else AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) fi + BOOST_LDFLAGS="" + BOOST_CPPFLAGS="" # execute ACTION-IF-NOT-FOUND (if present): ifelse([$3], , :, [$3]) else diff --git a/ax_boost_regex.m4 b/m4/ax_boost_regex.m4 index e2413c2..e2413c2 100644 --- a/ax_boost_regex.m4 +++ b/m4/ax_boost_regex.m4 diff --git a/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 index bd753b3..54191c5 100644 --- a/ax_check_compile_flag.m4 +++ b/m4/ax_check_compile_flag.m4 @@ -34,14 +34,24 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 6 +#serial 11 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl -AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ +AC_CACHE_CHECK([whether the _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + if test x"m4_case(_AC_LANG, + [C], [$GCC], + [C++], [$GXX], + [Fortran], [$GFC], + [Fortran 77], [$G77], + [Objective C], [$GOBJC], + [Objective C++], [$GOBJCXX], + [no])" = xyes ; then + add_gnu_werror="-Werror" + fi + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1 $add_gnu_werror" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) diff --git a/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4 index 03a30ce..03a30ce 100644 --- a/ax_check_link_flag.m4 +++ b/m4/ax_check_link_flag.m4 diff --git a/ax_require_defined.m4 b/m4/ax_require_defined.m4 index 17c3eab..17c3eab 100644 --- a/ax_require_defined.m4 +++ b/m4/ax_require_defined.m4 diff --git a/riscv/abstract_device.h b/riscv/abstract_device.h index 0726cd7..d8ddbab 100644 --- a/riscv/abstract_device.h +++ b/riscv/abstract_device.h @@ -16,6 +16,7 @@ class abstract_device_t { public: virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0; virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0; + virtual reg_t size() = 0; virtual ~abstract_device_t() {} virtual void tick(reg_t UNUSED rtc_ticks) {} }; diff --git a/riscv/arith.h b/riscv/arith.h index c60fcbe..b61b28c 100644 --- a/riscv/arith.h +++ b/riscv/arith.h @@ -32,15 +32,15 @@ inline uint64_t mulhu(uint64_t a, uint64_t b) inline int64_t mulh(int64_t a, int64_t b) { int negate = (a < 0) != (b < 0); - uint64_t res = mulhu(a < 0 ? -a : a, b < 0 ? -b : b); + uint64_t res = mulhu(a < 0 ? -(uint64_t)a : a, b < 0 ? -(uint64_t)b : b); return negate ? ~res + ((uint64_t)a * (uint64_t)b == 0) : res; } inline int64_t mulhsu(int64_t a, uint64_t b) { int negate = a < 0; - uint64_t res = mulhu(a < 0 ? -a : a, b); - return negate ? ~res + (a * b == 0) : res; + uint64_t res = mulhu(a < 0 ? -(uint64_t)a : a, b); + return negate ? ~res + ((uint64_t)a * b == 0) : res; } //ref: https://locklessinc.com/articles/sat_arithmetic/ diff --git a/riscv/cfg.cc b/riscv/cfg.cc index 67dfdb4..cc39a54 100644 --- a/riscv/cfg.cc +++ b/riscv/cfg.cc @@ -1,5 +1,6 @@ // See LICENSE for license details. +#include "config.h" #include "cfg.h" #include "mmu.h" #include "decode.h" @@ -17,13 +18,15 @@ bool mem_cfg_t::check_if_supported(reg_t base, reg_t size) // the regions in the first place, but we have them here to make sure that // we can't end up describing memory regions that don't make sense. They // ask that the page size is a multiple of the minimum page size, that the - // page is aligned to the minimum page size, that the page is non-empty and - // that the top address is still representable in a reg_t. + // page is aligned to the minimum page size, that the page is non-empty, + // that the size doesn't overflow size_t, and that the top address is still + // representable in a reg_t. // // Note: (base + size == 0) part of the assertion is to handle cases like // { base = 0xffff_ffff_ffff_f000, size: 0x1000 } return (size % PGSIZE == 0) && (base % PGSIZE == 0) && + (size_t(size) == size) && (size > 0) && ((base + size > base) || (base + size == 0)); } @@ -44,4 +47,5 @@ cfg_t::cfg_t() explicit_hartids = false; real_time_clint = false; trigger_count = 4; + cache_blocksz = 64; } diff --git a/riscv/cfg.h b/riscv/cfg.h index c972f03..8032856 100644 --- a/riscv/cfg.h +++ b/riscv/cfg.h @@ -6,6 +6,7 @@ #include <vector> #include "decode.h" #include <cassert> +class abstract_sim_if_t; typedef enum { endianness_little, @@ -77,6 +78,8 @@ public: bool explicit_hartids; bool real_time_clint; reg_t trigger_count; + reg_t cache_blocksz; + std::optional<abstract_sim_if_t*> external_simulator; size_t nprocs() const { return hartids.size(); } size_t max_hartid() const { return hartids.back(); } diff --git a/riscv/clint.cc b/riscv/clint.cc index 208ea0e..3d5c984 100644 --- a/riscv/clint.cc +++ b/riscv/clint.cc @@ -39,7 +39,8 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes) tick(0); - if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + static_assert(MSIP_BASE == 0); + if (/* addr >= MSIP_BASE && */ addr < MTIMECMP_BASE) { if (len == 8) { // Implement double-word loads as a pair of word loads return load(addr, 4, bytes) && load(addr + 4, 4, bytes + 4); @@ -68,7 +69,8 @@ bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes) if (len > 8) return false; - if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + static_assert(MSIP_BASE == 0); + if (/* addr >= MSIP_BASE && */ addr < MTIMECMP_BASE) { if (len == 8) { // Implement double-word stores as a pair of word stores return store(addr, 4, bytes) && store(addr + 4, 4, bytes + 4); @@ -117,7 +119,7 @@ void clint_t::tick(reg_t rtc_ticks) } clint_t* clint_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, - const std::vector<std::string>& UNUSED sargs) { + const std::vector<std::string>& sargs UNUSED) { if (fdt_parse_clint(fdt, base, "riscv,clint0") == 0 || fdt_parse_clint(fdt, base, "sifive,clint0") == 0) return new clint_t(sim, sim->CPU_HZ / sim->INSNS_PER_RTC_TICK, @@ -126,7 +128,7 @@ clint_t* clint_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, return nullptr; } -std::string clint_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) { +std::string clint_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex << " clint@" << CLINT_BASE << " {\n" diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc new file mode 100644 index 0000000..0acd1c7 --- /dev/null +++ b/riscv/csr_init.cc @@ -0,0 +1,552 @@ +#include "processor.h" +#include "debug_defines.h" + +void state_t::add_csr(reg_t addr, const csr_t_p& csr) +{ + csrmap[addr] = csr; +} + +#define add_const_ext_csr(ext, addr, csr) do { auto csr__ = (csr); if (proc->extension_enabled_const(ext)) { add_csr(addr, csr__); } } while (0) +#define add_ext_csr(ext, addr, csr) do { auto csr__ = (csr); if (proc->extension_enabled(ext)) { add_csr(addr, csr__); } } while (0) +#define add_user_csr(addr, csr) add_const_ext_csr('U', addr, csr) +#define add_supervisor_csr(addr, csr) add_const_ext_csr('S', addr, csr) +#define add_hypervisor_csr(addr, csr) add_ext_csr('H', addr, csr) + +void state_t::add_ireg_proxy(processor_t* const proc, sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg) +{ + // This assumes xlen is always max_xlen, which is true today (see + // mstatus_csr_t::unlogged_write()): + auto xlen = proc->get_isa().get_max_xlen(); + + const reg_t iprio0_addr = 0x30; + for (int i=0; i<16; i+=2) { + csr_t_p iprio = std::make_shared<aia_csr_t>(proc, iprio0_addr + i, 0, 0); + if (xlen == 32) { + ireg->add_ireg_proxy(iprio0_addr + i, std::make_shared<rv32_low_csr_t>(proc, iprio0_addr + i, iprio)); + ireg->add_ireg_proxy(iprio0_addr + i + 1, std::make_shared<rv32_high_csr_t>(proc, iprio0_addr + i + 1, iprio)); + } else { + ireg->add_ireg_proxy(iprio0_addr + i, iprio); + } + } +} + +void state_t::csr_init(processor_t* const proc, reg_t max_isa) +{ + // This assumes xlen is always max_xlen, which is true today (see + // mstatus_csr_t::unlogged_write()): + auto xlen = proc->get_isa().get_max_xlen(); + + add_csr(CSR_MISA, misa = std::make_shared<misa_csr_t>(proc, CSR_MISA, max_isa)); + mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_MSTATUS); + + if (xlen == 32) { + add_csr(CSR_MSTATUS, std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATUS, mstatus)); + add_csr(CSR_MSTATUSH, mstatush = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATUSH, mstatus)); + } else { + add_csr(CSR_MSTATUS, mstatus); + } + add_csr(CSR_MEPC, mepc = std::make_shared<epc_csr_t>(proc, CSR_MEPC)); + add_csr(CSR_MTVAL, mtval = std::make_shared<basic_csr_t>(proc, CSR_MTVAL, 0)); + add_csr(CSR_MSCRATCH, std::make_shared<basic_csr_t>(proc, CSR_MSCRATCH, 0)); + add_csr(CSR_MTVEC, mtvec = std::make_shared<tvec_csr_t>(proc, CSR_MTVEC)); + add_csr(CSR_MCAUSE, mcause = std::make_shared<cause_csr_t>(proc, CSR_MCAUSE)); + + const reg_t minstretcfg_mask = !proc->extension_enabled_const(EXT_SMCNTRPMF) ? 0 : + MHPMEVENT_MINH | MHPMEVENT_SINH | MHPMEVENT_UINH | MHPMEVENT_VSINH | MHPMEVENT_VUINH; + auto minstretcfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MINSTRETCFG, minstretcfg_mask, 0); + auto mcyclecfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MCYCLECFG, minstretcfg_mask, 0); + + minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET, minstretcfg); + mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE, mcyclecfg); + time = std::make_shared<time_counter_csr_t>(proc, CSR_TIME); + if (proc->extension_enabled_const(EXT_ZICNTR)) { + add_csr(CSR_INSTRET, std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRET, minstret)); + add_csr(CSR_CYCLE, std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLE, mcycle)); + add_csr(CSR_TIME, time_proxy = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time)); + } + if (xlen == 32) { + csr_t_p minstreth, mcycleh; + add_csr(CSR_MINSTRET, std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRET, minstret)); + add_csr(CSR_MINSTRETH, minstreth = std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETH, minstret)); + add_csr(CSR_MCYCLE, std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLE, mcycle)); + add_csr(CSR_MCYCLEH, mcycleh = std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLEH, mcycle)); + if (proc->extension_enabled_const(EXT_ZICNTR)) { + auto timeh = std::make_shared<rv32_high_csr_t>(proc, CSR_TIMEH, time); + add_csr(CSR_INSTRETH, std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRETH, minstreth)); + add_csr(CSR_CYCLEH, std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLEH, mcycleh)); + add_csr(CSR_TIMEH, std::make_shared<counter_proxy_csr_t>(proc, CSR_TIMEH, timeh)); + } + } else { + add_csr(CSR_MINSTRET, minstret); + add_csr(CSR_MCYCLE, mcycle); + } + for (reg_t i = 0; i < N_HPMCOUNTERS; ++i) { + const reg_t which_mevent = CSR_MHPMEVENT3 + i; + const reg_t which_meventh = CSR_MHPMEVENT3H + i; + const reg_t which_mcounter = CSR_MHPMCOUNTER3 + i; + const reg_t which_mcounterh = CSR_MHPMCOUNTER3H + i; + const reg_t which_counter = CSR_HPMCOUNTER3 + i; + const reg_t which_counterh = CSR_HPMCOUNTER3H + i; + mevent[i] = std::make_shared<mevent_csr_t>(proc, which_mevent); + auto mcounter = std::make_shared<const_csr_t>(proc, which_mcounter, 0); + add_csr(which_mcounter, mcounter); + + auto counter = std::make_shared<counter_proxy_csr_t>(proc, which_counter, mcounter); + add_const_ext_csr(EXT_ZIHPM, which_counter, counter); + + if (xlen == 32) { + add_csr(which_mevent, std::make_shared<rv32_low_csr_t>(proc, which_mevent, mevent[i])); + auto mcounterh = std::make_shared<const_csr_t>(proc, which_mcounterh, 0); + add_csr(which_mcounterh, mcounterh); + add_const_ext_csr(EXT_ZIHPM, which_counterh, std::make_shared<counter_proxy_csr_t>(proc, which_counterh, mcounterh)); + add_const_ext_csr(EXT_SSCOFPMF, which_meventh, std::make_shared<rv32_high_csr_t>(proc, which_meventh, mevent[i])); + } else { + add_csr(which_mevent, mevent[i]); + } + } + add_const_ext_csr(EXT_SSCOFPMF, CSR_SCOUNTOVF, std::make_shared<scountovf_csr_t>(proc, CSR_SCOUNTOVF)); + mie = std::make_shared<mie_csr_t>(proc, CSR_MIE); + mip = std::make_shared<mip_csr_t>(proc, CSR_MIP); + if (xlen == 32 && proc->extension_enabled_const(EXT_SMAIA)) { + add_csr(CSR_MIE, std::make_shared<rv32_low_csr_t>(proc, CSR_MIE, mie)); + add_csr(CSR_MIEH, std::make_shared<rv32_high_csr_t>(proc, CSR_MIEH, mie)); + add_csr(CSR_MIP, std::make_shared<rv32_low_csr_t>(proc, CSR_MIP, mip)); + add_csr(CSR_MIPH, std::make_shared<rv32_high_csr_t>(proc, CSR_MIPH, mip)); + } else { + add_csr(CSR_MIE, mie); + add_csr(CSR_MIP, mip); + } + auto sip_sie_accr = std::make_shared<generic_int_accessor_t>( + this, + ~MIP_HS_MASK, // read_mask + MIP_SSIP | MIP_LCOFIP, // ip_write_mask + ~MIP_HS_MASK, // ie_write_mask + generic_int_accessor_t::mask_mode_t::MIDELEG, + 0 // shiftamt + ); + + auto hip_hie_accr = std::make_shared<generic_int_accessor_t>( + this, + MIP_HS_MASK, // read_mask + MIP_VSSIP, // ip_write_mask + MIP_HS_MASK, // ie_write_mask + generic_int_accessor_t::mask_mode_t::MIDELEG, + 0 // shiftamt + ); + + auto vsip_vsie_accr = std::make_shared<generic_int_accessor_t>( + this, + MIP_VS_MASK, // read_mask + MIP_VSSIP, // ip_write_mask + MIP_VS_MASK, // ie_write_mask + generic_int_accessor_t::mask_mode_t::HIDELEG, + 1 // shiftamt + ); + + nonvirtual_sip = std::make_shared<sip_csr_t>(proc, CSR_SIP, sip_sie_accr); + auto vsip = std::make_shared<mip_proxy_csr_t>(proc, CSR_VSIP, vsip_vsie_accr); + auto sip = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sip, vsip); + if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { + add_hypervisor_csr(CSR_VSIP, std::make_shared<rv32_low_csr_t>(proc, CSR_VSIP, vsip)); + add_hypervisor_csr(CSR_VSIPH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_VSIPH, vsip)); + add_supervisor_csr(CSR_SIP, std::make_shared<rv32_low_csr_t>(proc, CSR_SIP, sip)); + add_supervisor_csr(CSR_SIPH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_SIPH, sip)); + } else { + add_hypervisor_csr(CSR_VSIP, vsip); + add_supervisor_csr(CSR_SIP, sip); + } + add_hypervisor_csr(CSR_HIP, std::make_shared<mip_proxy_csr_t>(proc, CSR_HIP, hip_hie_accr)); + hvip = std::make_shared<hvip_csr_t>(proc, CSR_HVIP, 0); + if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { + add_hypervisor_csr(CSR_HVIP, std::make_shared<rv32_low_csr_t>(proc, CSR_HVIP, hvip)); + add_hypervisor_csr(CSR_HVIPH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_HVIPH, hvip)); + } else { + add_hypervisor_csr(CSR_HVIP, hvip); + } + + nonvirtual_sie = std::make_shared<sie_csr_t>(proc, CSR_SIE, sip_sie_accr); + auto vsie = std::make_shared<mie_proxy_csr_t>(proc, CSR_VSIE, vsip_vsie_accr); + auto sie = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sie, vsie); + if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { + add_hypervisor_csr(CSR_VSIE, std::make_shared<rv32_low_csr_t>(proc, CSR_VSIE, vsie)); + add_hypervisor_csr(CSR_VSIEH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_VSIEH, vsie)); + add_supervisor_csr(CSR_SIE, std::make_shared<rv32_low_csr_t>(proc, CSR_SIE, sie)); + add_supervisor_csr(CSR_SIEH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_SIEH, sie)); + } else { + add_hypervisor_csr(CSR_VSIE, vsie); + add_supervisor_csr(CSR_SIE, sie); + } + add_hypervisor_csr(CSR_HIE, std::make_shared<mie_proxy_csr_t>(proc, CSR_HIE, hip_hie_accr)); + + add_supervisor_csr(CSR_MEDELEG, medeleg = std::make_shared<medeleg_csr_t>(proc, CSR_MEDELEG)); + mideleg = std::make_shared<mideleg_csr_t>(proc, CSR_MIDELEG); + if (xlen == 32 && proc->extension_enabled_const(EXT_SMAIA)) { + add_supervisor_csr(CSR_MIDELEG, std::make_shared<rv32_low_csr_t>(proc, CSR_MIDELEG, mideleg)); + add_supervisor_csr(CSR_MIDELEGH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_MIDELEGH, mideleg)); + } else { + add_supervisor_csr(CSR_MIDELEG, mideleg); + } + const reg_t counteren_mask = (proc->extension_enabled_const(EXT_ZICNTR) ? 0x7UL : 0x0) | (proc->extension_enabled_const(EXT_ZIHPM) ? 0xfffffff8ULL : 0x0); + add_user_csr(CSR_MCOUNTEREN, mcounteren = std::make_shared<masked_csr_t>(proc, CSR_MCOUNTEREN, counteren_mask, 0)); + add_csr(CSR_MCOUNTINHIBIT, mcountinhibit = std::make_shared<masked_csr_t>(proc, CSR_MCOUNTINHIBIT, counteren_mask & (~MCOUNTEREN_TIME), 0)); + add_supervisor_csr(CSR_SCOUNTEREN, scounteren = std::make_shared<masked_csr_t>(proc, CSR_SCOUNTEREN, counteren_mask, 0)); + nonvirtual_sepc = std::make_shared<epc_csr_t>(proc, CSR_SEPC); + add_hypervisor_csr(CSR_VSEPC, vsepc = std::make_shared<epc_csr_t>(proc, CSR_VSEPC)); + add_supervisor_csr(CSR_SEPC, sepc = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sepc, vsepc)); + nonvirtual_stval = std::make_shared<basic_csr_t>(proc, CSR_STVAL, 0); + add_hypervisor_csr(CSR_VSTVAL, vstval = std::make_shared<basic_csr_t>(proc, CSR_VSTVAL, 0)); + add_supervisor_csr(CSR_STVAL, stval = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stval, vstval)); + auto sscratch = std::make_shared<basic_csr_t>(proc, CSR_SSCRATCH, 0); + auto vsscratch = std::make_shared<basic_csr_t>(proc, CSR_VSSCRATCH, 0); + // Note: if max_isa does not include H, we don't really need this virtualized_csr_t at all (though it doesn't hurt): + add_supervisor_csr(CSR_SSCRATCH, std::make_shared<virtualized_csr_t>(proc, sscratch, vsscratch)); + add_hypervisor_csr(CSR_VSSCRATCH, vsscratch); + nonvirtual_stvec = std::make_shared<tvec_csr_t>(proc, CSR_STVEC); + add_hypervisor_csr(CSR_VSTVEC, vstvec = std::make_shared<tvec_csr_t>(proc, CSR_VSTVEC)); + add_supervisor_csr(CSR_STVEC, stvec = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stvec, vstvec)); + auto nonvirtual_satp = std::make_shared<satp_csr_t>(proc, CSR_SATP); + add_hypervisor_csr(CSR_VSATP, vsatp = std::make_shared<base_atp_csr_t>(proc, CSR_VSATP)); + add_supervisor_csr(CSR_SATP, satp = std::make_shared<virtualized_satp_csr_t>(proc, nonvirtual_satp, vsatp)); + nonvirtual_scause = std::make_shared<cause_csr_t>(proc, CSR_SCAUSE); + add_hypervisor_csr(CSR_VSCAUSE, vscause = std::make_shared<cause_csr_t>(proc, CSR_VSCAUSE)); + add_supervisor_csr(CSR_SCAUSE, scause = std::make_shared<virtualized_csr_t>(proc, nonvirtual_scause, vscause)); + mtval2 = std::make_shared<mtval2_csr_t>(proc, CSR_MTVAL2); + if (proc->extension_enabled('H') || proc->extension_enabled(EXT_SSDBLTRP)) + add_csr(CSR_MTVAL2, mtval2); + add_hypervisor_csr(CSR_MTINST, mtinst = std::make_shared<hypervisor_csr_t>(proc, CSR_MTINST)); + add_hypervisor_csr(CSR_HSTATUS, hstatus = std::make_shared<hstatus_csr_t>(proc, CSR_HSTATUS)); + add_hypervisor_csr(CSR_HGEIE, std::make_shared<const_csr_t>(proc, CSR_HGEIE, 0)); + add_hypervisor_csr(CSR_HGEIP, std::make_shared<const_csr_t>(proc, CSR_HGEIP, 0)); + hideleg = std::make_shared<hideleg_csr_t>(proc, CSR_HIDELEG, mideleg); + if (xlen == 32 && proc->extension_enabled_const(EXT_SSAIA)) { + add_hypervisor_csr(CSR_HIDELEG, std::make_shared<rv32_low_csr_t>(proc, CSR_HIDELEG, hideleg)); + add_hypervisor_csr(CSR_HIDELEGH, std::make_shared<aia_rv32_high_csr_t>(proc, CSR_HIDELEGH, hideleg)); + } else { + add_hypervisor_csr(CSR_HIDELEG, hideleg); + } + const reg_t hedeleg_mask = + (1 << CAUSE_MISALIGNED_FETCH) | + (1 << CAUSE_FETCH_ACCESS) | + (1 << CAUSE_ILLEGAL_INSTRUCTION) | + (1 << CAUSE_BREAKPOINT) | + (1 << CAUSE_MISALIGNED_LOAD) | + (1 << CAUSE_LOAD_ACCESS) | + (1 << CAUSE_MISALIGNED_STORE) | + (1 << CAUSE_STORE_ACCESS) | + (1 << CAUSE_USER_ECALL) | + (1 << CAUSE_FETCH_PAGE_FAULT) | + (1 << CAUSE_LOAD_PAGE_FAULT) | + (1 << CAUSE_STORE_PAGE_FAULT) | + (1 << CAUSE_SOFTWARE_CHECK_FAULT) | + (1 << CAUSE_HARDWARE_ERROR_FAULT); + add_hypervisor_csr(CSR_HEDELEG, hedeleg = std::make_shared<masked_csr_t>(proc, CSR_HEDELEG, hedeleg_mask, 0)); + add_hypervisor_csr(CSR_HCOUNTEREN, hcounteren = std::make_shared<masked_csr_t>(proc, CSR_HCOUNTEREN, counteren_mask, 0)); + htimedelta = std::make_shared<basic_csr_t>(proc, CSR_HTIMEDELTA, 0); + if (xlen == 32) { + add_hypervisor_csr(CSR_HTIMEDELTA, std::make_shared<rv32_low_csr_t>(proc, CSR_HTIMEDELTA, htimedelta)); + add_hypervisor_csr(CSR_HTIMEDELTAH, std::make_shared<rv32_high_csr_t>(proc, CSR_HTIMEDELTAH, htimedelta)); + } else { + add_hypervisor_csr(CSR_HTIMEDELTA, htimedelta); + } + add_hypervisor_csr(CSR_HTVAL, htval = std::make_shared<basic_csr_t>(proc, CSR_HTVAL, 0)); + add_hypervisor_csr(CSR_HTINST, htinst = std::make_shared<basic_csr_t>(proc, CSR_HTINST, 0)); + add_hypervisor_csr(CSR_HGATP, hgatp = std::make_shared<hgatp_csr_t>(proc, CSR_HGATP)); + nonvirtual_sstatus = std::make_shared<sstatus_proxy_csr_t>(proc, CSR_SSTATUS, mstatus); + add_hypervisor_csr(CSR_VSSTATUS, vsstatus = std::make_shared<vsstatus_csr_t>(proc, CSR_VSSTATUS)); + add_supervisor_csr(CSR_SSTATUS, sstatus = std::make_shared<sstatus_csr_t>(proc, nonvirtual_sstatus, vsstatus)); + + add_csr(CSR_DPC, dpc = std::make_shared<dpc_csr_t>(proc, CSR_DPC)); + add_csr(CSR_DSCRATCH0, std::make_shared<debug_mode_csr_t>(proc, CSR_DSCRATCH0)); + add_csr(CSR_DSCRATCH1, std::make_shared<debug_mode_csr_t>(proc, CSR_DSCRATCH1)); + add_csr(CSR_DCSR, dcsr = std::make_shared<dcsr_csr_t>(proc, CSR_DCSR)); + + add_csr(CSR_TSELECT, tselect = std::make_shared<tselect_csr_t>(proc, CSR_TSELECT)); + if (proc->get_cfg().trigger_count > 0) { + add_csr(CSR_TDATA1, std::make_shared<tdata1_csr_t>(proc, CSR_TDATA1)); + add_csr(CSR_TDATA2, tdata2 = std::make_shared<tdata2_csr_t>(proc, CSR_TDATA2)); + add_csr(CSR_TDATA3, std::make_shared<tdata3_csr_t>(proc, CSR_TDATA3)); + add_csr(CSR_TINFO, std::make_shared<tinfo_csr_t>(proc, CSR_TINFO)); + if (!proc->extension_enabled_const('S')) { + add_csr(CSR_TCONTROL, tcontrol = std::make_shared<masked_csr_t>(proc, CSR_TCONTROL, CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE, 0)); + } + } else { + add_csr(CSR_TDATA1, std::make_shared<const_csr_t>(proc, CSR_TDATA1, 0)); + add_csr(CSR_TDATA2, tdata2 = std::make_shared<const_csr_t>(proc, CSR_TDATA2, 0)); + add_csr(CSR_TDATA3, std::make_shared<const_csr_t>(proc, CSR_TDATA3, 0)); + add_csr(CSR_TINFO, std::make_shared<const_csr_t>(proc, CSR_TINFO, 0)); + } + unsigned scontext_length = (xlen == 32 ? 16 : 32); // debug spec suggests 16-bit for RV32 and 32-bit for RV64 + add_supervisor_csr(CSR_SCONTEXT, scontext = std::make_shared<masked_csr_t>(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0)); + unsigned hcontext_length = (xlen == 32 ? 6 : 13) + (proc->extension_enabled('H') ? 1 : 0); // debug spec suggest 7-bit (6-bit) for RV32 and 14-bit (13-bit) for RV64 with (without) H extension + auto hcontext = std::make_shared<masked_csr_t>(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); + add_hypervisor_csr(CSR_HCONTEXT, hcontext); + add_csr(CSR_MCONTEXT, mcontext = std::make_shared<proxy_csr_t>(proc, CSR_MCONTEXT, hcontext)); + add_csr(CSR_MSECCFG, mseccfg = std::make_shared<mseccfg_csr_t>(proc, CSR_MSECCFG)); + + for (int i = 0; i < max_pmp; ++i) { + add_csr(CSR_PMPADDR0 + i, pmpaddr[i] = std::make_shared<pmpaddr_csr_t>(proc, CSR_PMPADDR0 + i)); + } + for (int i = 0; i < max_pmp; i += xlen / 8) { + reg_t addr = CSR_PMPCFG0 + i / 4; + add_csr(addr, std::make_shared<pmpcfg_csr_t>(proc, addr)); + } + + add_csr(CSR_FFLAGS, fflags = std::make_shared<float_csr_t>(proc, CSR_FFLAGS, FSR_AEXC >> FSR_AEXC_SHIFT, 0)); + add_csr(CSR_FRM, frm = std::make_shared<float_csr_t>(proc, CSR_FRM, FSR_RD >> FSR_RD_SHIFT, 0)); + assert(FSR_AEXC_SHIFT == 0); // composite_csr_t assumes fflags begins at bit 0 + add_csr(CSR_FCSR, std::make_shared<composite_csr_t>(proc, CSR_FCSR, frm, fflags, FSR_RD_SHIFT)); + + add_ext_csr(EXT_ZKR, CSR_SEED, std::make_shared<seed_csr_t>(proc, CSR_SEED)); + + add_csr(CSR_MARCHID, std::make_shared<const_csr_t>(proc, CSR_MARCHID, 5)); + add_csr(CSR_MIMPID, std::make_shared<const_csr_t>(proc, CSR_MIMPID, 0)); + add_csr(CSR_MVENDORID, std::make_shared<const_csr_t>(proc, CSR_MVENDORID, 0)); + add_csr(CSR_MHARTID, std::make_shared<const_csr_t>(proc, CSR_MHARTID, proc->get_id())); + add_csr(CSR_MCONFIGPTR, std::make_shared<const_csr_t>(proc, CSR_MCONFIGPTR, 0)); + const reg_t menvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? MENVCFG_CBCFE | MENVCFG_CBIE : 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE : 0) | + (proc->extension_enabled(EXT_SMNPM) ? MENVCFG_PMM : 0) | + (proc->extension_enabled(EXT_SVADU) ? MENVCFG_ADUE: 0) | + (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) | + (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0) | + (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? MENVCFG_SSE : 0) | + (proc->extension_enabled(EXT_SSDBLTRP) ? MENVCFG_DTE : 0)| + (proc->extension_enabled(EXT_SMCDELEG) ? MENVCFG_CDE : 0); + menvcfg = std::make_shared<envcfg_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, 0); + if (xlen == 32) { + add_user_csr(CSR_MENVCFG, std::make_shared<rv32_low_csr_t>(proc, CSR_MENVCFG, menvcfg)); + add_user_csr(CSR_MENVCFGH, std::make_shared<rv32_high_csr_t>(proc, CSR_MENVCFGH, menvcfg)); + } else { + add_user_csr(CSR_MENVCFG, menvcfg); + } + const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE : 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0) | + (proc->extension_enabled(EXT_SSNPM) ? SENVCFG_PMM : 0) | + (proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? SENVCFG_SSE : 0); + add_supervisor_csr(CSR_SENVCFG, senvcfg = std::make_shared<senvcfg_csr_t>(proc, CSR_SENVCFG, senvcfg_mask, 0)); + const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE : 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE : 0) | + (proc->extension_enabled(EXT_SSNPM) ? HENVCFG_PMM : 0) | + (proc->extension_enabled(EXT_SVADU) ? HENVCFG_ADUE: 0) | + (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) | + (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0) | + (proc->extension_enabled(EXT_ZICFILP) ? HENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? HENVCFG_SSE : 0) | + (proc->extension_enabled(EXT_SSDBLTRP) ? HENVCFG_DTE : 0); + henvcfg = std::make_shared<henvcfg_csr_t>(proc, CSR_HENVCFG, henvcfg_mask, 0, menvcfg); + if (xlen == 32) { + add_hypervisor_csr(CSR_HENVCFG, std::make_shared<rv32_low_csr_t>(proc, CSR_HENVCFG, henvcfg)); + add_hypervisor_csr(CSR_HENVCFGH, std::make_shared<rv32_high_csr_t>(proc, CSR_HENVCFGH, henvcfg)); + } else { + add_hypervisor_csr(CSR_HENVCFG, henvcfg); + } + if (proc->extension_enabled_const(EXT_SMSTATEEN)) { + const reg_t sstateen0_mask = (proc->extension_enabled(EXT_ZFINX) ? SSTATEEN0_FCSR : 0) | + (proc->extension_enabled(EXT_ZCMT) ? SSTATEEN0_JVT : 0) | + SSTATEEN0_CS; + const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_CSRIND | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN; + const reg_t mstateen0_mask = hstateen0_mask | (proc->extension_enabled(EXT_SSQOSID) ? MSTATEEN0_PRIV114 : 0); + for (int i = 0; i < 4; i++) { + const reg_t mstateen_mask = i == 0 ? mstateen0_mask : MSTATEEN_HSTATEEN; + mstateen[i] = std::make_shared<masked_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0); + if (xlen == 32) { + add_csr(CSR_MSTATEEN0 + i, std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen[i])); + add_csr(CSR_MSTATEEN0H + i, std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATEEN0H + i, mstateen[i])); + } else { + add_csr(CSR_MSTATEEN0 + i, mstateen[i]); + } + + const reg_t hstateen_mask = i == 0 ? hstateen0_mask : HSTATEEN_SSTATEEN; + hstateen[i] = std::make_shared<hstateen_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen_mask, 0, i); + if (xlen == 32) { + add_hypervisor_csr(CSR_HSTATEEN0 + i, std::make_shared<rv32_low_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen[i])); + add_hypervisor_csr(CSR_HSTATEEN0H + i, std::make_shared<rv32_high_csr_t>(proc, CSR_HSTATEEN0H + i, hstateen[i])); + } else { + add_hypervisor_csr(CSR_HSTATEEN0 + i, hstateen[i]); + } + + const reg_t sstateen_mask = i == 0 ? sstateen0_mask : 0; + add_supervisor_csr(CSR_SSTATEEN0 + i, sstateen[i] = std::make_shared<sstateen_csr_t>(proc, CSR_SSTATEEN0 + i, sstateen_mask, 0, i)); + } + } + + if (proc->extension_enabled_const(EXT_SMRNMI)) { + add_csr(CSR_MNSCRATCH, std::make_shared<basic_csr_t>(proc, CSR_MNSCRATCH, 0)); + add_csr(CSR_MNEPC, mnepc = std::make_shared<epc_csr_t>(proc, CSR_MNEPC)); + add_csr(CSR_MNCAUSE, std::make_shared<const_csr_t>(proc, CSR_MNCAUSE, (reg_t)1 << (xlen - 1))); + add_csr(CSR_MNSTATUS, mnstatus = std::make_shared<mnstatus_csr_t>(proc, CSR_MNSTATUS)); + } + + if (proc->extension_enabled_const(EXT_SSTC)) { + stimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_STIMECMP, MIP_STIP); + vstimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_VSTIMECMP, MIP_VSTIP); + auto virtualized_stimecmp = std::make_shared<virtualized_with_special_permission_csr_t>(proc, stimecmp, vstimecmp); + if (xlen == 32) { + add_supervisor_csr(CSR_STIMECMP, std::make_shared<rv32_low_csr_t>(proc, CSR_STIMECMP, virtualized_stimecmp)); + add_supervisor_csr(CSR_STIMECMPH, std::make_shared<rv32_high_csr_t>(proc, CSR_STIMECMPH, virtualized_stimecmp)); + add_hypervisor_csr(CSR_VSTIMECMP, std::make_shared<rv32_low_csr_t>(proc, CSR_VSTIMECMP, vstimecmp)); + add_hypervisor_csr(CSR_VSTIMECMPH, std::make_shared<rv32_high_csr_t>(proc, CSR_VSTIMECMPH, vstimecmp)); + } else { + add_supervisor_csr(CSR_STIMECMP, virtualized_stimecmp); + add_hypervisor_csr(CSR_VSTIMECMP, vstimecmp); + } + } + + add_ext_csr(EXT_ZCMT, CSR_JVT, jvt = std::make_shared<jvt_csr_t>(proc, CSR_JVT, 0)); + + const reg_t ssp_mask = -reg_t(xlen / 8); + add_ext_csr(EXT_ZICFISS, CSR_SSP, ssp = std::make_shared<ssp_csr_t>(proc, CSR_SSP, ssp_mask, 0)); + + // Smcdeleg + if (proc->extension_enabled_const(EXT_SMCDELEG) || proc->extension_enabled_const(EXT_SSCCFG)) { + add_supervisor_csr(CSR_SCOUNTINHIBIT, scountinhibit = std::make_shared<scntinhibit_csr_t>(proc, CSR_SCOUNTINHIBIT, mcountinhibit)); + } + + // Smcsrind / Sscsrind + if (proc->extension_enabled_const(EXT_SMCSRIND)) { + csr_t_p miselect = std::make_shared<basic_csr_t>(proc, CSR_MISELECT, 0); + add_csr(CSR_MISELECT, miselect); + + sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg; + add_csr(CSR_MIREG, mireg = std::make_shared<sscsrind_reg_csr_t>(proc, CSR_MIREG, miselect)); + add_ireg_proxy(proc, mireg); + const reg_t mireg_csrs[] = { CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; + for (auto csr : mireg_csrs) + add_csr(csr, std::make_shared<sscsrind_reg_csr_t>(proc, csr, miselect)); + } + + if (proc->extension_enabled_const(EXT_SSCSRIND)) { + csr_t_p vsiselect = std::make_shared<siselect_csr_t>(proc, CSR_VSISELECT, 0); + add_hypervisor_csr(CSR_VSISELECT, vsiselect); + + csr_t_p siselect = std::make_shared<siselect_csr_t>(proc, CSR_SISELECT, 0); + add_supervisor_csr(CSR_SISELECT, std::make_shared<virtualized_with_special_permission_csr_t>(proc, siselect, vsiselect)); + + auto vsireg = std::make_shared<sscsrind_reg_csr_t>(proc, CSR_VSIREG, vsiselect); + add_hypervisor_csr(CSR_VSIREG, vsireg); + + auto sireg = std::make_shared<sscsrind_reg_csr_t>(proc, CSR_SIREG, siselect); + add_ireg_proxy(proc, sireg); + add_supervisor_csr(CSR_SIREG, std::make_shared<virtualized_indirect_csr_t>(proc, sireg, vsireg)); + + const reg_t vsireg_csrs[] = { CSR_VSIREG2, CSR_VSIREG3, CSR_VSIREG4, CSR_VSIREG5, CSR_VSIREG6 }; + const reg_t sireg_csrs[] = { CSR_SIREG2, CSR_SIREG3, CSR_SIREG4, CSR_SIREG5, CSR_SIREG6 }; + for (size_t i = 0; i < std::size(vsireg_csrs); i++) { + auto vsireg = std::make_shared<sscsrind_reg_csr_t>(proc, vsireg_csrs[i], vsiselect); + add_hypervisor_csr(vsireg_csrs[i], vsireg); + + auto sireg = std::make_shared<sscsrind_reg_csr_t>(proc, sireg_csrs[i], siselect); + add_supervisor_csr(sireg_csrs[i], std::make_shared<virtualized_indirect_csr_t>(proc, sireg, vsireg)); + + // Smcdeleg + if (proc->extension_enabled(EXT_SSCCFG) || proc->extension_enabled(EXT_SMCDELEG)) { + switch (sireg_csrs[i]) { + case CSR_SIREG: + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcycle); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, minstret); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3 + j]); + } + break; + case CSR_SIREG4: + if (xlen == 32) { + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, csrmap[CSR_CYCLEH]); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, csrmap[CSR_INSTRETH]); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3H + j]); + } + } + break; + case CSR_SIREG2: + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcyclecfg); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRETCFG, minstretcfg); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMEVENT_3 + j, csrmap[CSR_MHPMEVENT3H + j]); + } + break; + case CSR_SIREG5: + if (xlen == 32) { + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcycle); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, minstret); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3 + j]); + } + } + case CSR_SIREG3: + case CSR_SIREG6: + default: + break; + } + } + } + } + + if (proc->extension_enabled_const(EXT_SMCNTRPMF)) { + if (xlen == 32) { + add_csr(CSR_MCYCLECFG, std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLECFG, mcyclecfg)); + add_csr(CSR_MCYCLECFGH, std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLECFGH, mcyclecfg)); + add_csr(CSR_MINSTRETCFG, std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRETCFG, minstretcfg)); + add_csr(CSR_MINSTRETCFGH, std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETCFGH, minstretcfg)); + } else { + add_csr(CSR_MCYCLECFG, mcyclecfg); + add_csr(CSR_MINSTRETCFG, minstretcfg); + } + } + + const reg_t srmcfg_mask = SRMCFG_MCID | SRMCFG_RCID; + add_const_ext_csr(EXT_SSQOSID, CSR_SRMCFG, std::make_shared<srmcfg_csr_t>(proc, CSR_SRMCFG, srmcfg_mask, 0)); + + mvien = std::make_shared<masked_csr_t>(proc, CSR_MVIEN, MIP_SEIP | MIP_SSIP, 0); + mvip = std::make_shared<mvip_csr_t>(proc, CSR_MVIP, 0); + if (proc->extension_enabled_const(EXT_SMAIA)) { + add_csr(CSR_MTOPI, std::make_shared<mtopi_csr_t>(proc, CSR_MTOPI)); + if (xlen == 32) { + add_supervisor_csr(CSR_MVIEN, std::make_shared<rv32_low_csr_t>(proc, CSR_MVIEN, mvien)); + add_supervisor_csr(CSR_MVIENH, std::make_shared<rv32_high_csr_t>(proc, CSR_MVIENH, mvien)); + add_supervisor_csr(CSR_MVIP, std::make_shared<rv32_low_csr_t>(proc, CSR_MVIP, mvip)); + add_supervisor_csr(CSR_MVIPH, std::make_shared<rv32_high_csr_t>(proc, CSR_MVIPH, mvip)); + } else { + add_supervisor_csr(CSR_MVIEN, mvien); + add_supervisor_csr(CSR_MVIP, mvip); + } + } + + hvictl = std::make_shared<aia_csr_t>(proc, CSR_HVICTL, HVICTL_VTI | HVICTL_IID | HVICTL_DPR | HVICTL_IPRIOM | HVICTL_IPRIO, 0); + vstopi = std::make_shared<vstopi_csr_t>(proc, CSR_VSTOPI); + if (proc->extension_enabled_const(EXT_SSAIA)) { // Included by EXT_SMAIA + csr_t_p nonvirtual_stopi = std::make_shared<nonvirtual_stopi_csr_t>(proc, CSR_STOPI); + add_supervisor_csr(CSR_STOPI, std::make_shared<virtualized_with_special_permission_csr_t>(proc, nonvirtual_stopi, vstopi)); + add_supervisor_csr(CSR_STOPEI, std::make_shared<inaccessible_csr_t>(proc, CSR_STOPEI)); + auto hvien = std::make_shared<aia_csr_t>(proc, CSR_HVIEN, 0, 0); + auto hviprio1 = std::make_shared<aia_csr_t>(proc, CSR_HVIPRIO1, 0, 0); + auto hviprio2 = std::make_shared<aia_csr_t>(proc, CSR_HVIPRIO2, 0, 0); + if (xlen == 32) { + add_hypervisor_csr(CSR_HVIEN, std::make_shared<rv32_low_csr_t>(proc, CSR_HVIEN, hvien)); + add_hypervisor_csr(CSR_HVIENH, std::make_shared<rv32_high_csr_t>(proc, CSR_HVIENH, hvien)); + add_hypervisor_csr(CSR_HVIPRIO1, std::make_shared<rv32_low_csr_t>(proc, CSR_HVIPRIO1, hviprio1)); + add_hypervisor_csr(CSR_HVIPRIO1H, std::make_shared<rv32_high_csr_t>(proc, CSR_HVIPRIO1H, hviprio1)); + add_hypervisor_csr(CSR_HVIPRIO2, std::make_shared<rv32_low_csr_t>(proc, CSR_HVIPRIO2, hviprio2)); + add_hypervisor_csr(CSR_HVIPRIO2H, std::make_shared<rv32_high_csr_t>(proc, CSR_HVIPRIO2H, hviprio2)); + } else { + add_hypervisor_csr(CSR_HVIEN, hvien); + add_hypervisor_csr(CSR_HVIPRIO1, hviprio1); + add_hypervisor_csr(CSR_HVIPRIO2, hviprio2); + } + add_hypervisor_csr(CSR_HVICTL, hvictl); + add_hypervisor_csr(CSR_VSTOPI, vstopi); + } +} diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 02a2c4f..3a32712 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -15,6 +15,8 @@ #include "insn_macros.h" // For CSR_DCSR_V: #include "debug_defines.h" +// For ctz: +#include "arith.h" // STATE macro used by require_privilege() macro: #undef STATE @@ -197,13 +199,13 @@ bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx) const noe if (mseccfg_mml) { if (cfgx && cfgw && cfgr && cfgl) { // Locked Shared data region: Read only on both M and S/U mode. - return typer; + return typer && !hlvx; } else { const bool mml_shared_region = !cfgr && cfgw; const bool mml_chk_normal = (prvm == cfgl) && normal_rwx; const bool mml_chk_shared = - (!cfgl && cfgx && (typer || typew)) || - (!cfgl && !cfgx && (typer || (typew && prvm))) || + (!cfgl && cfgx && ((typer && !hlvx) || typew)) || + (!cfgl && !cfgx && ((typer && !hlvx) || (typew && prvm))) || (cfgl && typex) || (cfgl && typer && cfgx && prvm); return mml_shared_region ? mml_chk_shared : mml_chk_normal; @@ -286,7 +288,9 @@ mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr): void mseccfg_csr_t::verify_permissions(insn_t insn, bool write) const { basic_csr_t::verify_permissions(insn, write); if (!proc->extension_enabled(EXT_SMEPMP) && - !proc->extension_enabled(EXT_ZICFILP)) + !proc->extension_enabled(EXT_SMMPM) && + !proc->extension_enabled(EXT_ZICFILP) && + !proc->extension_enabled(EXT_ZKR)) throw trap_illegal_instruction(insn.bits()); } @@ -302,32 +306,51 @@ bool mseccfg_csr_t::get_rlb() const noexcept { return (read() & MSECCFG_RLB); } -bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept { - if (proc->n_pmp == 0) - return false; +bool mseccfg_csr_t::get_useed() const noexcept { + return (read() & MSECCFG_USEED); +} - // pmpcfg.L is 1 in any rule or entry (including disabled entries) - const bool pmplock_recorded = std::any_of(state->pmpaddr, state->pmpaddr + proc->n_pmp, - [](const pmpaddr_csr_t_p & c) { return c->is_locked(); } ); +bool mseccfg_csr_t::get_sseed() const noexcept { + return (read() & MSECCFG_SSEED); +} + +bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept { reg_t new_val = read(); - // When RLB is 0 and pmplock_recorded, RLB is locked to 0. - // Otherwise set the RLB bit according val - if (!(pmplock_recorded && (read() & MSECCFG_RLB) == 0)) { - new_val &= ~MSECCFG_RLB; - new_val |= (val & MSECCFG_RLB); - } + if (proc->n_pmp != 0) { + // pmpcfg.L is 1 in any rule or entry (including disabled entries) + const bool pmplock_recorded = std::any_of(state->pmpaddr, state->pmpaddr + proc->n_pmp, + [](const pmpaddr_csr_t_p & c) { return c->is_locked(); } ); - new_val |= (val & MSECCFG_MMWP); //MMWP is sticky - new_val |= (val & MSECCFG_MML); //MML is sticky + // When RLB is 0 and pmplock_recorded, RLB is locked to 0. + // Otherwise set the RLB bit according val + if (!(pmplock_recorded && (read() & MSECCFG_RLB) == 0)) { + new_val &= ~MSECCFG_RLB; + new_val |= (val & MSECCFG_RLB); + } - proc->get_mmu()->flush_tlb(); + new_val |= (val & MSECCFG_MMWP); //MMWP is sticky + new_val |= (val & MSECCFG_MML); //MML is sticky + + proc->get_mmu()->flush_tlb(); + } + + if (proc->extension_enabled(EXT_ZKR)) { + uint64_t mask = MSECCFG_USEED | MSECCFG_SSEED; + new_val = (new_val & ~mask) | (val & mask); + } if (proc->extension_enabled(EXT_ZICFILP)) { new_val &= ~MSECCFG_MLPE; new_val |= (val & MSECCFG_MLPE); } + if (proc->extension_enabled(EXT_SMMPM)) { + const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM + reg_t pmm = get_field(val, MSECCFG_PMM); + new_val = set_field(new_val, MSECCFG_PMM, pmm != pmm_reserved ? pmm : 0); + } + return basic_csr_t::unlogged_write(new_val); } @@ -421,6 +444,7 @@ reg_t base_status_csr_t::compute_sstatus_write_mask() const noexcept { | (proc->any_custom_extensions() ? SSTATUS_XS : 0) | (has_vs ? SSTATUS_VS : 0) | (proc->extension_enabled(EXT_ZICFILP) ? SSTATUS_SPELP : 0) + | (proc->extension_enabled(EXT_SSDBLTRP) ? SSTATUS_SDT : 0) ; } @@ -464,12 +488,23 @@ vsstatus_csr_t::vsstatus_csr_t(processor_t* const proc, const reg_t addr): } bool vsstatus_csr_t::unlogged_write(const reg_t val) noexcept { - const reg_t newval = (this->val & ~sstatus_write_mask) | (val & sstatus_write_mask); + const reg_t hDTE = (state->henvcfg->read() & HENVCFG_DTE); + const reg_t adj_write_mask = sstatus_write_mask & ~(hDTE ? 0 : SSTATUS_SDT); + reg_t newval = (this->val & ~adj_write_mask) | (val & adj_write_mask); + + newval = (newval & SSTATUS_SDT) ? (newval & ~SSTATUS_SIE) : newval; + if (state->v) maybe_flush_tlb(newval); this->val = adjust_sd(newval); return true; } +reg_t vsstatus_csr_t::read() const noexcept { + const reg_t hDTE = state->henvcfg->read() & HENVCFG_DTE; + const reg_t adj_read_mask = sstatus_read_mask & ~(hDTE ? 0 : SSTATUS_SDT); + return this->val & adj_read_mask; +} + // implement class sstatus_proxy_csr_t sstatus_proxy_csr_t::sstatus_proxy_csr_t(processor_t* const proc, const reg_t addr, mstatus_csr_t_p mstatus): base_status_csr_t(proc, addr), @@ -477,16 +512,26 @@ sstatus_proxy_csr_t::sstatus_proxy_csr_t(processor_t* const proc, const reg_t ad } bool sstatus_proxy_csr_t::unlogged_write(const reg_t val) noexcept { - const reg_t new_mstatus = (mstatus->read() & ~sstatus_write_mask) | (val & sstatus_write_mask); + const reg_t mDTE = (state->menvcfg->read() & MENVCFG_DTE); + const reg_t adj_write_mask = sstatus_write_mask & ~(mDTE ? 0 : SSTATUS_SDT); + reg_t new_mstatus = (mstatus->read() & ~adj_write_mask) | (val & adj_write_mask); + + new_mstatus = (new_mstatus & SSTATUS_SDT) ? (new_mstatus & ~SSTATUS_SIE) : new_mstatus; // On RV32 this will only log the low 32 bits, so make sure we're // not modifying anything in the upper 32 bits. - assert((sstatus_write_mask & 0xffffffffU) == sstatus_write_mask); + assert((adj_write_mask & 0xffffffffU) == adj_write_mask); mstatus->write(new_mstatus); return false; // avoid double logging: already logged by mstatus->write() } +reg_t sstatus_proxy_csr_t::read() const noexcept { + const reg_t mDTE = state->menvcfg->read() & MENVCFG_DTE; + const reg_t adj_read_mask = sstatus_read_mask & ~(mDTE ? 0 : SSTATUS_SDT); + return mstatus->read() & adj_read_mask; +} + // implement class mstatus_csr_t mstatus_csr_t::mstatus_csr_t(processor_t* const proc, const reg_t addr): base_status_csr_t(proc, addr), @@ -505,12 +550,16 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept { | (has_page ? MSTATUS_TVM : 0) | (has_gva ? MSTATUS_GVA : 0) | (has_mpv ? MSTATUS_MPV : 0) + | (proc->extension_enabled(EXT_SMDBLTRP) ? MSTATUS_MDT : 0) | (proc->extension_enabled(EXT_ZICFILP) ? (MSTATUS_SPELP | MSTATUS_MPELP) : 0) + | (proc->extension_enabled(EXT_SSDBLTRP) ? SSTATUS_SDT : 0) ; const reg_t requested_mpp = proc->legalize_privilege(get_field(val, MSTATUS_MPP)); const reg_t adjusted_val = set_field(val, MSTATUS_MPP, requested_mpp); - const reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); + reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); + new_mstatus = (new_mstatus & MSTATUS_MDT) ? (new_mstatus & ~MSTATUS_MIE) : new_mstatus; + new_mstatus = (new_mstatus & MSTATUS_SDT) ? (new_mstatus & ~MSTATUS_SIE) : new_mstatus; maybe_flush_tlb(new_mstatus); this->val = adjust_sd(new_mstatus); return true; @@ -525,6 +574,7 @@ reg_t mstatus_csr_t::compute_mstatus_initial_value() const noexcept { | (proc->extension_enabled_const('U') && (proc->get_const_xlen() != 32) ? set_field((reg_t)0, MSTATUS_UXL, xlen_to_uxl(proc->get_const_xlen())) : 0) | (proc->extension_enabled_const('S') && (proc->get_const_xlen() != 32) ? set_field((reg_t)0, MSTATUS_SXL, xlen_to_uxl(proc->get_const_xlen())) : 0) | (proc->get_mmu()->is_target_big_endian() ? big_endian_bits : 0) + | (proc->extension_enabled(EXT_SMDBLTRP) ? MSTATUS_MDT : 0) | 0; // initial value for mstatus } @@ -537,6 +587,7 @@ bool mnstatus_csr_t::unlogged_write(const reg_t val) noexcept { // NMIE can be set but not cleared const reg_t mask = (~read() & MNSTATUS_NMIE) | (proc->extension_enabled('H') ? MNSTATUS_MNPV : 0) + | (proc->extension_enabled(EXT_ZICFILP) ? MNSTATUS_MNPELP : 0) | MNSTATUS_MNPP; const reg_t requested_mnpp = proc->legalize_privilege(get_field(val, MNSTATUS_MNPP)); @@ -590,6 +641,22 @@ reg_t rv32_high_csr_t::written_value() const noexcept { return (orig->written_value() >> 32) & 0xffffffffU; } +aia_rv32_high_csr_t::aia_rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig): + rv32_high_csr_t(proc, addr, orig) { +} + +void aia_rv32_high_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_AIA)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_AIA)) + throw trap_virtual_instruction(insn.bits()); + } + + rv32_high_csr_t::verify_permissions(insn, write); +} + // implement class sstatus_csr_t sstatus_csr_t::sstatus_csr_t(processor_t* const proc, sstatus_proxy_csr_t_p orig, vsstatus_csr_t_p virt): virtualized_csr_t(proc, orig, virt), @@ -619,11 +686,6 @@ bool sstatus_csr_t::enabled(const reg_t which) { if (!state->v || (virt_sstatus->read() & which) != 0) return true; } - - // If the field doesn't exist, it is always enabled. See #823. - if (!orig_sstatus->field_exists(which)) - return true; - return false; } @@ -699,9 +761,9 @@ bool misa_csr_t::unlogged_write(const reg_t val) noexcept { state->mie->write_with_mask(MIP_HS_MASK, 0); // also takes care of hie, sie state->mip->write_with_mask(MIP_HS_MASK, 0); // also takes care of hip, sip, hvip state->hstatus->write(0); - for (reg_t i = 3; i < N_HPMCOUNTERS + 3; ++i) { - const reg_t new_mevent = state->mevent[i - 3]->read() & ~(MHPMEVENT_VUINH | MHPMEVENT_VSINH); - state->mevent[i - 3]->write(new_mevent); + for (reg_t i = 0; i < N_HPMCOUNTERS; ++i) { + const reg_t new_mevent = state->mevent[i]->read() & ~(MHPMEVENT_VUINH | MHPMEVENT_VSINH); + state->mevent[i]->write(new_mevent); } } @@ -737,8 +799,14 @@ mip_csr_t::mip_csr_t(processor_t* const proc, const reg_t addr): mip_or_mie_csr_t(proc, addr) { } +void mip_csr_t::write_with_mask(const reg_t mask, const reg_t val) noexcept { + if (!(state->mvien->read() & MIP_SEIP) && (mask & MIP_SEIP)) + state->mvip->write_with_mask(MIP_SEIP, val); // mvip.SEIP is an alias of mip.SEIP when mvien.SEIP=0 + mip_or_mie_csr_t::write_with_mask(mask & ~MIP_SEIP, val); +} + reg_t mip_csr_t::read() const noexcept { - return val | state->hvip->basic_csr_t::read(); + return val | state->hvip->basic_csr_t::read() | ((state->mvien->read() & MIP_SEIP) ? 0 : (state->mvip->basic_csr_t::read() & MIP_SEIP)); } void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept { @@ -820,6 +888,15 @@ mip_proxy_csr_t::mip_proxy_csr_t(processor_t* const proc, const reg_t addr, gene accr(accr) { } +void mip_proxy_csr_t::verify_permissions(insn_t insn, bool write) const { + csr_t::verify_permissions(insn, write); + if (proc->extension_enabled_const(EXT_SSAIA) && proc->extension_enabled('H')) { + if ((state->csrmap[CSR_HVICTL]->read() & HVICTL_VTI) && + proc->extension_enabled('S') && state->v) + throw trap_virtual_instruction(insn.bits()); // VS-mode attempts to access sip when hvictl.VTI=1 + } +} + reg_t mip_proxy_csr_t::read() const noexcept { return accr->ip_read(); } @@ -835,6 +912,15 @@ mie_proxy_csr_t::mie_proxy_csr_t(processor_t* const proc, const reg_t addr, gene accr(accr) { } +void mie_proxy_csr_t::verify_permissions(insn_t insn, bool write) const { + csr_t::verify_permissions(insn, write); + if (proc->extension_enabled_const(EXT_SSAIA) && proc->extension_enabled('H')) { + if ((state->csrmap[CSR_HVICTL]->read() & HVICTL_VTI) && + proc->extension_enabled('S') && state->v) + throw trap_virtual_instruction(insn.bits()); // VS-mode attempts to access sie when hvictl.VTI=1 + } +} + reg_t mie_proxy_csr_t::read() const noexcept { return accr->ie_read(); } @@ -907,10 +993,43 @@ bool medeleg_csr_t::unlogged_write(const reg_t val) noexcept { | (1 << CAUSE_STORE_PAGE_FAULT) | (proc->extension_enabled('H') ? hypervisor_exceptions : 0) | (1 << CAUSE_SOFTWARE_CHECK_FAULT) + | (1 << CAUSE_HARDWARE_ERROR_FAULT) ; return basic_csr_t::unlogged_write((read() & ~mask) | (val & mask)); } +sip_csr_t::sip_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr): + mip_proxy_csr_t(proc, addr, accr) { +} + +reg_t sip_csr_t::read() const noexcept { + const reg_t mask = ~state->mideleg->read() & state->mvien->read(); + return (mip_proxy_csr_t::read() & ~mask) | (state->mvip->read() & mask); +} + +bool sip_csr_t::unlogged_write(const reg_t val) noexcept { + const reg_t mask = ~state->mideleg->read() & state->mvien->read(); + state->mvip->write_with_mask(mask & accr->get_ip_write_mask(), val); + return mip_proxy_csr_t::unlogged_write(val & ~mask); +} + +sie_csr_t::sie_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr): + mie_proxy_csr_t(proc, addr, accr), + val(0) { +} + +reg_t sie_csr_t::read() const noexcept { + const reg_t mask = ~state->mideleg->read() & state->mvien->read(); + return (mie_proxy_csr_t::read() & ~mask) | (val & mask); +} + +bool sie_csr_t::unlogged_write(const reg_t val) noexcept { + const reg_t mask = ~state->mideleg->read() & state->mvien->read(); + this->val = (this->val & ~mask) | (val & mask); + mie_proxy_csr_t::unlogged_write(val & ~mask); + return true; +} + // implement class masked_csr_t masked_csr_t::masked_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init): basic_csr_t(proc, addr, init), @@ -930,7 +1049,15 @@ envcfg_csr_t::envcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_ bool envcfg_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t cbie_reserved = 2; // Reserved value of xenvcfg.CBIE - const reg_t adjusted_val = get_field(val, MENVCFG_CBIE) != cbie_reserved ? val : set_field(val, MENVCFG_CBIE, 0); + reg_t adjusted_val = get_field(val, MENVCFG_CBIE) != cbie_reserved ? val : set_field(val, MENVCFG_CBIE, 0); + + const reg_t pmm_reserved = 1; // Reserved value of xseccfg.PMM + const reg_t pmm = get_field(adjusted_val, MENVCFG_PMM); + adjusted_val = set_field(adjusted_val, MENVCFG_PMM, pmm != pmm_reserved ? pmm : 0); + + if (get_field(adjusted_val, MENVCFG_PMM) != get_field(read(), MENVCFG_PMM)) + proc->get_mmu()->flush_tlb(); + return masked_csr_t::unlogged_write(adjusted_val); } @@ -1022,6 +1149,7 @@ bool virtualized_satp_csr_t::unlogged_write(const reg_t val) noexcept { wide_counter_csr_t::wide_counter_csr_t(processor_t* const proc, const reg_t addr, smcntrpmf_csr_t_p config_csr): csr_t(proc, addr), val(0), + written(false), config_csr(config_csr) { } @@ -1030,7 +1158,15 @@ reg_t wide_counter_csr_t::read() const noexcept { } void wide_counter_csr_t::bump(const reg_t howmuch) noexcept { - if (is_counting_enabled()) { + if (written) { + // Because writing a CSR serializes the simulator, howmuch should + // reflect exactly one instruction: the explicit CSR write. + // If counting is disabled, though, howmuch will be zero. + assert(howmuch <= 1); + // The ISA mandates that explicit writes to instret take precedence + // over the instret, so simply skip the increment. + written = false; + } else if (is_counting_enabled()) { val += howmuch; // to keep log reasonable size, don't log every bump } // Clear cached value @@ -1038,23 +1174,15 @@ void wide_counter_csr_t::bump(const reg_t howmuch) noexcept { } bool wide_counter_csr_t::unlogged_write(const reg_t val) noexcept { + // Because writing a CSR serializes the simulator and is followed by a + // bump, back-to-back writes with no intervening bump should never occur. + assert(!written); + written = true; + this->val = val; - // The ISA mandates that if an instruction writes instret, the write - // takes precedence over the increment to instret. However, Spike - // unconditionally increments instret after executing an instruction. - // Correct for this artifact by decrementing instret here. - // Ensure that Smctrpmf hasn't disabled counting. - if (is_counting_enabled()) { - this->val--; - } return true; } -reg_t wide_counter_csr_t::written_value() const noexcept { - // Re-adjust for upcoming bump() - return this->val + 1; -} - // Returns true if counting is not inhibited by Smcntrpmf. // Note that minstretcfg / mcyclecfg / mhpmevent* share the same inhibit bits. bool wide_counter_csr_t::is_counting_enabled() const noexcept { @@ -1177,7 +1305,7 @@ hideleg_csr_t::hideleg_csr_t(processor_t* const proc, const reg_t addr, csr_t_p reg_t hideleg_csr_t::read() const noexcept { return masked_csr_t::read() & mideleg->read(); -}; +} hgatp_csr_t::hgatp_csr_t(processor_t* const proc, const reg_t addr): basic_csr_t(proc, addr, 0) { @@ -1292,9 +1420,11 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr): ebreaku(false), ebreakvs(false), ebreakvu(false), - halt(false), v(false), + mprven(false), cause(0), + ext_cause(0), + cetrig(0), pelp(elp_t::NO_LP_EXPECTED) { } @@ -1306,18 +1436,22 @@ void dcsr_csr_t::verify_permissions(insn_t insn, bool write) const { reg_t dcsr_csr_t::read() const noexcept { reg_t result = 0; - result = set_field(result, DCSR_XDEBUGVER, 1); + result = set_field(result, DCSR_XDEBUGVER, 4); result = set_field(result, DCSR_EBREAKM, ebreakm); result = set_field(result, DCSR_EBREAKS, ebreaks); result = set_field(result, DCSR_EBREAKU, ebreaku); result = set_field(result, CSR_DCSR_EBREAKVS, ebreakvs); result = set_field(result, CSR_DCSR_EBREAKVU, ebreakvu); - result = set_field(result, DCSR_STOPCYCLE, 0); + result = set_field(result, DCSR_STOPCOUNT, 0); result = set_field(result, DCSR_STOPTIME, 0); result = set_field(result, DCSR_CAUSE, cause); + result = set_field(result, DCSR_EXTCAUSE, ext_cause); + if (proc->extension_enabled(EXT_SMDBLTRP)) + result = set_field(result, DCSR_CETRIG, cetrig); result = set_field(result, DCSR_STEP, step); result = set_field(result, DCSR_PRV, prv); result = set_field(result, CSR_DCSR_V, v); + result = set_field(result, DCSR_MPRVEN, mprven); result = set_field(result, DCSR_PELP, pelp); return result; } @@ -1331,16 +1465,18 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept { ebreaku = proc->extension_enabled('U') ? get_field(val, DCSR_EBREAKU) : false; ebreakvs = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_EBREAKVS) : false; ebreakvu = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_EBREAKVU) : false; - halt = get_field(val, DCSR_HALT); v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false; + mprven = get_field(val, CSR_DCSR_MPRVEN); pelp = proc->extension_enabled(EXT_ZICFILP) ? static_cast<elp_t>(get_field(val, DCSR_PELP)) : elp_t::NO_LP_EXPECTED; + cetrig = proc->extension_enabled(EXT_SMDBLTRP) ? get_field(val, DCSR_CETRIG) : false; return true; } -void dcsr_csr_t::update_fields(const uint8_t cause, const reg_t prv, +void dcsr_csr_t::update_fields(const uint8_t cause, uint8_t ext_cause, const reg_t prv, const bool v, const elp_t pelp) noexcept { this->cause = cause; + this->ext_cause = ext_cause; this->prv = prv; this->v = v; this->pelp = pelp; @@ -1353,8 +1489,9 @@ float_csr_t::float_csr_t(processor_t* const proc, const reg_t addr, const reg_t void float_csr_t::verify_permissions(insn_t insn, bool write) const { masked_csr_t::verify_permissions(insn, write); - require_fs; - if (!proc->extension_enabled('F') && !proc->extension_enabled(EXT_ZFINX)) + + if (!((proc->extension_enabled('F') && STATE.sstatus->enabled(SSTATUS_FS)) + || proc->extension_enabled(EXT_ZFINX))) throw trap_illegal_instruction(insn.bits()); if (proc->extension_enabled(EXT_SMSTATEEN) && proc->extension_enabled(EXT_ZFINX)) { @@ -1374,7 +1511,8 @@ void float_csr_t::verify_permissions(insn_t insn, bool write) const { } bool float_csr_t::unlogged_write(const reg_t val) noexcept { - dirty_fp_state; + if (!proc->extension_enabled(EXT_ZFINX)) + dirty_fp_state; return masked_csr_t::unlogged_write(val); } @@ -1411,6 +1549,16 @@ void seed_csr_t::verify_permissions(insn_t insn, bool write) const { if (!proc->extension_enabled(EXT_ZKR) || !write) throw trap_illegal_instruction(insn.bits()); csr_t::verify_permissions(insn, write); + + if (state->v) { + if (state->mseccfg->get_sseed() && write) + throw trap_virtual_instruction(insn.bits()); + else + throw trap_illegal_instruction(insn.bits()); + } else if ((state->prv == PRV_U && !state->mseccfg->get_useed()) || + (state->prv == PRV_S && !state->mseccfg->get_sseed())) { + throw trap_illegal_instruction(insn.bits()); + } } reg_t seed_csr_t::read() const noexcept { @@ -1428,7 +1576,7 @@ vector_csr_t::vector_csr_t(processor_t* const proc, const reg_t addr, const reg_ } void vector_csr_t::verify_permissions(insn_t insn, bool write) const { - require_vector_vs; + require(proc->any_vector_extensions() && STATE.sstatus->enabled(SSTATUS_VS)); basic_csr_t::verify_permissions(insn, write); } @@ -1449,7 +1597,7 @@ vxsat_csr_t::vxsat_csr_t(processor_t* const proc, const reg_t addr): } void vxsat_csr_t::verify_permissions(insn_t insn, bool write) const { - require_vector_vs; + require(proc->any_vector_extensions() && STATE.sstatus->enabled(SSTATUS_VS)); masked_csr_t::verify_permissions(insn, write); } @@ -1538,6 +1686,18 @@ void senvcfg_csr_t::verify_permissions(insn_t insn, bool write) const { masked_csr_t::verify_permissions(insn, write); } +// senvcfg.sse is read_only 0 when menvcfg.sse = 0 +reg_t senvcfg_csr_t::read() const noexcept { + reg_t envcfg = state->v ? state->henvcfg->read() : state->menvcfg->read(); + return masked_csr_t::read() & ~(envcfg & MENVCFG_SSE ? 0 : MENVCFG_SSE); +} + +bool senvcfg_csr_t::unlogged_write(const reg_t val) noexcept { + reg_t envcfg = state->v ? state->henvcfg->read() : state->menvcfg->read(); + const reg_t mask = envcfg | ~MENVCFG_SSE; + return envcfg_csr_t::unlogged_write((masked_csr_t::read() & ~mask) | (val & mask)); +} + void henvcfg_csr_t::verify_permissions(insn_t insn, bool write) const { if (proc->extension_enabled(EXT_SMSTATEEN)) { if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_HENVCFG)) @@ -1548,7 +1708,7 @@ void henvcfg_csr_t::verify_permissions(insn_t insn, bool write) const { } bool henvcfg_csr_t::unlogged_write(const reg_t val) noexcept { - const reg_t mask = menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE | MENVCFG_ADUE); + const reg_t mask = menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE | MENVCFG_ADUE | MENVCFG_DTE | MENVCFG_SSE); return envcfg_csr_t::unlogged_write((masked_csr_t::read() & ~mask) | (val & mask)); } @@ -1562,10 +1722,6 @@ bool stimecmp_csr_t::unlogged_write(const reg_t val) noexcept { return basic_csr_t::unlogged_write(val); } -virtualized_stimecmp_csr_t::virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt): - virtualized_csr_t(proc, orig, virt) { -} - void stimecmp_csr_t::verify_permissions(insn_t insn, bool write) const { if (!(state->menvcfg->read() & MENVCFG_STCE)) { // access to (v)stimecmp with MENVCFG.STCE = 0 @@ -1581,9 +1737,18 @@ void stimecmp_csr_t::verify_permissions(insn_t insn, bool write) const { } basic_csr_t::verify_permissions(insn, write); + + if (proc->extension_enabled_const(EXT_SSAIA) && proc->extension_enabled('H')) { + if ((state->csrmap[CSR_HVICTL]->read() & HVICTL_VTI) && state->v && write) + throw trap_virtual_instruction(insn.bits()); + } +} + +virtualized_with_special_permission_csr_t::virtualized_with_special_permission_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt): + virtualized_csr_t(proc, orig, virt) { } -void virtualized_stimecmp_csr_t::verify_permissions(insn_t insn, bool write) const { +void virtualized_with_special_permission_csr_t::verify_permissions(insn_t insn, bool write) const { orig_csr->verify_permissions(insn, write); } @@ -1594,14 +1759,22 @@ scountovf_csr_t::scountovf_csr_t(processor_t* const proc, const reg_t addr): void scountovf_csr_t::verify_permissions(insn_t insn, bool write) const { if (!proc->extension_enabled(EXT_SSCOFPMF)) throw trap_illegal_instruction(insn.bits()); + + if (proc->extension_enabled('H') && + (proc->extension_enabled_const(EXT_SMCDELEG) || proc->extension_enabled(EXT_SSCCFG)) + ) { + if (state->v && (state->menvcfg->read() & MENVCFG_CDE)) { + throw trap_virtual_instruction(insn.bits()); + } + } csr_t::verify_permissions(insn, write); } reg_t scountovf_csr_t::read() const noexcept { reg_t val = 0; - for (reg_t i = 3; i < N_HPMCOUNTERS + 3; ++i) { - bool of = state->mevent[i - 3]->read() & MHPMEVENT_OF; - val |= of << i; + for (reg_t i = 0; i < N_HPMCOUNTERS; ++i) { + bool of = state->mevent[i]->read() & MHPMEVENT_OF; + val |= of << (i + FIRST_HPMCOUNTER); } /* In M and S modes, scountovf bit X is readable when mcounteren bit X is set, */ @@ -1663,10 +1836,74 @@ sscsrind_reg_csr_t::sscsrind_reg_csr_t(processor_t* const proc, const reg_t addr } void sscsrind_reg_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) + throw trap_illegal_instruction(insn.bits()); + } + // Don't call base verify_permission for VS registers remapped to S-mode if (insn.csr() == address) csr_t::verify_permissions(insn, write); + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_CSRIND)) + throw trap_virtual_instruction(insn.bits()); + } + + if (proc->extension_enabled(EXT_SMCDELEG)) { + if (insn.csr() >= CSR_VSIREG && insn.csr() <= CSR_VSIREG6) { + if (!state->v) { + // An attempt to access any vsireg* from M or S mode raises an illegal instruction exception. + throw trap_illegal_instruction(insn.bits()); + } else { + if (state->prv == PRV_S) { + // An attempt from VS-mode to access any vsireg raises an illegal instruction + // exception if menvcfg.CDE = 0, or a virtual instruction exception if menvcfg.CDE = 1 + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } + if (insn.csr() >= CSR_SIREG && insn.csr() <= CSR_SIREG6) { + // attempts to access any sireg* when menvcfg.CDE = 0; + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + if (!state->v) { + throw trap_illegal_instruction(insn.bits()); + } else { + if (state->prv == PRV_S) { + // An attempt from VS-mode to access any sireg* causes illegal instruction exception if menvcfg.CDE = 0 + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } else { + // menvcfg.CDE = 1; + if (state->v) { + // An attempt from VS-mode to access any sireg* causes a virtual instruction exception if menvcfg.CDE = 1 + throw trap_virtual_instruction(insn.bits()); + } + // counter selected by siselect is not delegated to S-mode (the corresponding bit in mcounteren = 0). + auto iselect_addr = iselect->read(); + if (iselect_addr >= SISELECT_SMCDELEG_START && iselect_addr <= SISELECT_SMCDELEG_END) { + reg_t counter_id_offset = iselect_addr - SISELECT_SMCDELEG_START; + if (!(state->mcounteren->read() & (1U << counter_id_offset))) { + if (!state->v) { + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } + } + } + } + csr_t_p proxy_csr = get_reg(); if (proxy_csr == nullptr) { if (!state->v) { @@ -1728,9 +1965,7 @@ srmcfg_csr_t::srmcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_ masked_csr_t(proc, addr, mask, init) { } -void srmcfg_csr_t::verify_permissions(insn_t insn, bool write) const { - csr_t::verify_permissions(insn, write); - +void srmcfg_csr_t::verify_permissions(insn_t insn, bool write UNUSED) const { if (!proc->extension_enabled(EXT_SSQOSID)) throw trap_illegal_instruction(insn.bits()); @@ -1741,6 +1976,10 @@ void srmcfg_csr_t::verify_permissions(insn_t insn, bool write) const { if (state->v) throw trap_virtual_instruction(insn.bits()); + + if (state->prv < PRV_S) { + throw trap_illegal_instruction(insn.bits()); + } } hvip_csr_t::hvip_csr_t(processor_t* const proc, const reg_t addr, const reg_t init): @@ -1765,3 +2004,229 @@ void ssp_csr_t::verify_permissions(insn_t insn, bool write) const { DECLARE_XENVCFG_VARS(SSE); require_envcfg(SSE); } + +mtval2_csr_t::mtval2_csr_t(processor_t* const proc, const reg_t addr): + hypervisor_csr_t(proc, addr) { +} + +void mtval2_csr_t::verify_permissions(insn_t insn, bool write) const { + basic_csr_t::verify_permissions(insn, write); + if (!proc->extension_enabled('H') && !proc->extension_enabled(EXT_SSDBLTRP)) + throw trap_illegal_instruction(insn.bits()); +} + +hstatus_csr_t::hstatus_csr_t(processor_t* const proc, const reg_t addr): + basic_csr_t(proc, addr, set_field((reg_t)0, HSTATUS_VSXL, xlen_to_uxl(proc->get_const_xlen()))) { +} + +bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept { + const reg_t mask = HSTATUS_VTSR | HSTATUS_VTW + | (proc->supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0) + | (proc->extension_enabled(EXT_SSNPM) ? HSTATUS_HUPMM : 0) + | HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA; + + const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM + reg_t pmm = get_field(val, HSTATUS_HUPMM); + const reg_t adjusted_val = set_field(val, HSTATUS_HUPMM, pmm != pmm_reserved ? pmm : 0); + + const reg_t new_hstatus = (read() & ~mask) | (adjusted_val & mask); + if (get_field(new_hstatus, HSTATUS_HUPMM) != get_field(read(), HSTATUS_HUPMM)) + proc->get_mmu()->flush_tlb(); + return basic_csr_t::unlogged_write(new_hstatus); +} + +scntinhibit_csr_t::scntinhibit_csr_t(processor_t* const proc, const reg_t addr, csr_t_p mcountinhibit): + basic_csr_t(proc, addr, mcountinhibit->read()) { +} + +void scntinhibit_csr_t::verify_permissions(insn_t insn, bool write) const { + if (insn.csr() == address) { + csr_t::verify_permissions(insn, write); + } + + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + throw trap_illegal_instruction(insn.bits()); + } +} + +bool scntinhibit_csr_t::unlogged_write(const reg_t val) noexcept { + state->mcountinhibit->write(state->mcounteren->read() & val); + return true; +} + +reg_t scntinhibit_csr_t::read() const noexcept { + return state->mcounteren->read() & state->mcountinhibit->read(); +} + +mtopi_csr_t::mtopi_csr_t(processor_t* const proc, const reg_t addr): + csr_t(proc, addr) { +} + +reg_t mtopi_csr_t::read() const noexcept { + reg_t enabled_interrupts = state->mip->read() & state->mie->read() & ~state->mideleg->read(); + if (!enabled_interrupts) + return 0; // no enabled pending interrupt to M-mode + + reg_t selected_interrupt = proc->select_an_interrupt_with_default_priority(enabled_interrupts); + reg_t identity = ctz(selected_interrupt); + return set_field((reg_t)1, MTOPI_IID, identity); // IPRIO always 1 if iprio array is RO0 +} + +bool mtopi_csr_t::unlogged_write(const reg_t UNUSED val) noexcept { + return false; +} + +mvip_csr_t::mvip_csr_t(processor_t* const proc, const reg_t addr, const reg_t init): + basic_csr_t(proc, addr, init) { +} + +reg_t mvip_csr_t::read() const noexcept { + const reg_t val = basic_csr_t::read(); + const reg_t mvien = state->mvien->read(); + const reg_t mip = state->mip->read(); + const reg_t menvcfg = state->menvcfg->read(); + return 0 + | (val & MIP_SEIP) + | ((menvcfg & MENVCFG_STCE) ? 0 : (mip & MIP_STIP)) + | (((mvien & MIP_SSIP) ? val : mip) & MIP_SSIP) + ; +} + +bool mvip_csr_t::unlogged_write(const reg_t val) noexcept { + if (!(state->menvcfg->read() & MENVCFG_STCE)) + state->mip->write_with_mask(MIP_STIP, val); // mvip.STIP is an alias of mip.STIP when mip.STIP is writable + if (!(state->mvien->read() & MIP_SSIP)) + state->mip->write_with_mask(MIP_SSIP, val); // mvip.SSIP is an alias of mip.SSIP when mvien.SSIP=0 + + const reg_t new_val = (val & MIP_SEIP) | (((state->mvien->read() & MIP_SSIP) ? val : basic_csr_t::read()) & MIP_SSIP); + return basic_csr_t::unlogged_write(new_val); +} + +void mvip_csr_t::write_with_mask(const reg_t mask, const reg_t val) noexcept { + basic_csr_t::unlogged_write((basic_csr_t::read() & ~mask) | (val & mask)); + log_write(); +} + +nonvirtual_stopi_csr_t::nonvirtual_stopi_csr_t(processor_t* const proc, const reg_t addr): + csr_t(proc, addr) { +} + +void nonvirtual_stopi_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_AIA)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_AIA)) + throw trap_virtual_instruction(insn.bits()); + } + + csr_t::verify_permissions(insn, write); +} + +reg_t nonvirtual_stopi_csr_t::read() const noexcept { + reg_t enabled_interrupts = state->nonvirtual_sip->read() & state->nonvirtual_sie->read() & ~state->hideleg->read(); + if (!enabled_interrupts) + return 0; // no enabled pending interrupt to S-mode + + reg_t selected_interrupt = proc->select_an_interrupt_with_default_priority(enabled_interrupts); + reg_t identity = ctz(selected_interrupt); + return set_field((reg_t)1, MTOPI_IID, identity); // IPRIO always 1 if iprio array is RO0 +} + +bool nonvirtual_stopi_csr_t::unlogged_write(const reg_t UNUSED val) noexcept { + return false; +} + +inaccessible_csr_t::inaccessible_csr_t(processor_t* const proc, const reg_t addr): + csr_t(proc, addr) { +} + +void inaccessible_csr_t::verify_permissions(insn_t insn, bool write) const { + if (state->v) + throw trap_virtual_instruction(insn.bits()); + else + throw trap_illegal_instruction(insn.bits()); +} + +vstopi_csr_t::vstopi_csr_t(processor_t* const proc, const reg_t addr): + csr_t(proc, addr) { +} + +void vstopi_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_AIA)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_AIA)) + throw trap_virtual_instruction(insn.bits()); + } + + csr_t::verify_permissions(insn, write); +} + +reg_t vstopi_csr_t::read() const noexcept { + reg_t hvictl = state->hvictl->read(); + bool vti = hvictl & HVICTL_VTI; + reg_t iid = get_field(hvictl, HVICTL_IID); + bool dpr = hvictl & HVICTL_DPR; + bool ipriom = hvictl & HVICTL_IPRIOM; + reg_t iprio = get_field(hvictl, HVICTL_IPRIO); + + reg_t enabled_interrupts = state->mip->read() & state->mie->read() & state->hideleg->read(); + enabled_interrupts >>= 1; // VSSIP -> SSIP, etc + reg_t vgein = get_field(state->hstatus->read(), HSTATUS_VGEIN); + reg_t virtual_sei_priority = (vgein == 0 && iid == IRQ_S_EXT && iprio != 0) ? iprio : 255; // vstopi.IPRIO is 255 for priority number 256 + + reg_t identity, priority; + if (vti) { + if (!(enabled_interrupts & MIP_SEIP) && iid == IRQ_S_EXT) + return 0; + + identity = ((enabled_interrupts & MIP_SEIP) && (iid == IRQ_S_EXT || dpr)) ? IRQ_S_EXT : iid; + priority = (identity == IRQ_S_EXT) ? virtual_sei_priority : ((iprio != 0 || !dpr) ? iprio : 255); + } else { + if (!enabled_interrupts) + return 0; // no enabled pending interrupt to VS-mode + + reg_t selected_interrupt = proc->select_an_interrupt_with_default_priority(enabled_interrupts); + identity = ctz(selected_interrupt); + priority = (identity == IRQ_S_EXT) ? virtual_sei_priority : 255; // vstopi.IPRIO is 255 for interrupt with default priority lower than VSEI + } + return set_field((reg_t)(ipriom ? priority : 1), MTOPI_IID, identity); +} + +bool vstopi_csr_t::unlogged_write(const reg_t UNUSED val) noexcept { + return false; +} + +siselect_csr_t::siselect_csr_t(processor_t* const proc, const reg_t addr, const reg_t init): + basic_csr_t(proc, addr, init) { +} + +void siselect_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_CSRIND)) + throw trap_virtual_instruction(insn.bits()); + } + + basic_csr_t::verify_permissions(insn, write); +} + +aia_csr_t::aia_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init): + masked_csr_t(proc, addr, mask, init) { +} + +void aia_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_AIA)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_AIA)) + throw trap_virtual_instruction(insn.bits()); + } + + basic_csr_t::verify_permissions(insn, write); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 658ffdb..f076aaa 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -150,6 +150,8 @@ class mseccfg_csr_t: public basic_csr_t { bool get_mml() const noexcept; bool get_mmwp() const noexcept; bool get_rlb() const noexcept; + bool get_useed() const noexcept; + bool get_sseed() const noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; @@ -234,13 +236,12 @@ typedef std::shared_ptr<base_status_csr_t> base_status_csr_t_p; // For vsstatus, which is its own separate architectural register // (unlike sstatus) +// vstatus.sdt is read_only 0 when henvcfg.dte = 0 class vsstatus_csr_t final: public base_status_csr_t { public: vsstatus_csr_t(processor_t* const proc, const reg_t addr); - reg_t read() const noexcept override { - return val; - } + virtual reg_t read() const noexcept override; protected: virtual bool unlogged_write(const reg_t val) noexcept override; @@ -300,13 +301,18 @@ class rv32_high_csr_t: public csr_t { csr_t_p orig; }; +class aia_rv32_high_csr_t: public rv32_high_csr_t { + public: + aia_rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +// sstatus.sdt is read_only 0 when menvcfg.dte = 0 class sstatus_proxy_csr_t final: public base_status_csr_t { public: sstatus_proxy_csr_t(processor_t* const proc, const reg_t addr, mstatus_csr_t_p mstatus); - reg_t read() const noexcept override { - return mstatus->read() & sstatus_read_mask; - } + virtual reg_t read() const noexcept override; protected: virtual bool unlogged_write(const reg_t val) noexcept override; @@ -356,7 +362,7 @@ class mip_or_mie_csr_t: public csr_t { mip_or_mie_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override; - void write_with_mask(const reg_t mask, const reg_t val) noexcept; + virtual void write_with_mask(const reg_t mask, const reg_t val) noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override final; @@ -371,6 +377,8 @@ class mip_csr_t: public mip_or_mie_csr_t { mip_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override final; + void write_with_mask(const reg_t mask, const reg_t val) noexcept override; + // Does not log. Used by external things (clint) that wiggle bits in mip. void backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept; private: @@ -406,6 +414,7 @@ class generic_int_accessor_t { void ip_write(const reg_t val) noexcept; reg_t ie_read() const noexcept; void ie_write(const reg_t val) noexcept; + reg_t get_ip_write_mask() { return ip_write_mask; } private: state_t* const state; const reg_t read_mask; @@ -423,10 +432,10 @@ typedef std::shared_ptr<generic_int_accessor_t> generic_int_accessor_t_p; class mip_proxy_csr_t: public csr_t { public: mip_proxy_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr); + virtual void verify_permissions(insn_t insn, bool write) const override; virtual reg_t read() const noexcept override; protected: virtual bool unlogged_write(const reg_t val) noexcept override; - private: generic_int_accessor_t_p accr; }; @@ -434,6 +443,7 @@ class mip_proxy_csr_t: public csr_t { class mie_proxy_csr_t: public csr_t { public: mie_proxy_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr); + virtual void verify_permissions(insn_t insn, bool write) const override; virtual reg_t read() const noexcept override; protected: virtual bool unlogged_write(const reg_t val) noexcept override; @@ -460,6 +470,24 @@ class medeleg_csr_t: public basic_csr_t { const reg_t hypervisor_exceptions; }; +class sip_csr_t: public mip_proxy_csr_t { + public: + sip_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr); + virtual reg_t read() const noexcept override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +class sie_csr_t: public mie_proxy_csr_t { + public: + sie_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr); + virtual reg_t read() const noexcept override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; + private: + reg_t val; +}; + // For CSRs with certain bits hardwired class masked_csr_t: public basic_csr_t { public: @@ -480,14 +508,14 @@ class envcfg_csr_t: public masked_csr_t { // henvcfg.pbmte is read_only 0 when menvcfg.pbmte = 0 // henvcfg.stce is read_only 0 when menvcfg.stce = 0 // henvcfg.hade is read_only 0 when menvcfg.hade = 0 +// henvcfg.dte is read_only 0 when menvcfg.dte = 0 +// henvcfg.sse is read_only 0 when menvcfg.sse = 0 class henvcfg_csr_t final: public envcfg_csr_t { public: henvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, csr_t_p menvcfg); - reg_t read() const noexcept override { - return (menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE | MENVCFG_ADUE)) & masked_csr_t::read(); + return (menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE | MENVCFG_ADUE | MENVCFG_DTE | MENVCFG_SSE)) & masked_csr_t::read(); } - virtual void verify_permissions(insn_t insn, bool write) const override; protected: @@ -542,10 +570,10 @@ class wide_counter_csr_t: public csr_t { void bump(const reg_t howmuch) noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; - virtual reg_t written_value() const noexcept override; private: bool is_counting_enabled() const noexcept; reg_t val; + bool written; smcntrpmf_csr_t_p config_csr; }; @@ -684,7 +712,7 @@ class dcsr_csr_t: public csr_t { dcsr_csr_t(processor_t* const proc, const reg_t addr); virtual void verify_permissions(insn_t insn, bool write) const override; virtual reg_t read() const noexcept override; - void update_fields(const uint8_t cause, const reg_t prv, + void update_fields(const uint8_t cause, const uint8_t ext_cause, const reg_t prv, const bool v, const elp_t pelp) noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; @@ -696,9 +724,11 @@ class dcsr_csr_t: public csr_t { bool ebreaku; bool ebreakvs; bool ebreakvu; - bool halt; bool v; + bool mprven; uint8_t cause; + uint8_t ext_cause; + bool cetrig; elp_t pelp; }; @@ -787,7 +817,11 @@ class sstateen_csr_t: public hstateen_csr_t { class senvcfg_csr_t final: public envcfg_csr_t { public: senvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + reg_t read() const noexcept override; virtual void verify_permissions(insn_t insn, bool write) const override; + + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; }; class stimecmp_csr_t: public basic_csr_t { @@ -800,9 +834,9 @@ class stimecmp_csr_t: public basic_csr_t { reg_t intr_mask; }; -class virtualized_stimecmp_csr_t: public virtualized_csr_t { +class virtualized_with_special_permission_csr_t: public virtualized_csr_t { public: - virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt); + virtualized_with_special_permission_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt); virtual void verify_permissions(insn_t insn, bool write) const override; }; @@ -880,4 +914,87 @@ class ssp_csr_t final : public masked_csr_t { ssp_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); virtual void verify_permissions(insn_t insn, bool write) const override; }; + +// mtval2 CSR provided by H extension - but required if Ssdbltrp is implemented +class mtval2_csr_t: public hypervisor_csr_t { + public: + mtval2_csr_t(processor_t* const proc, const reg_t addr); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class hstatus_csr_t final: public basic_csr_t { + public: + hstatus_csr_t(processor_t* const proc, const reg_t addr); + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +class scntinhibit_csr_t: public basic_csr_t { + public: + scntinhibit_csr_t(processor_t* const proc, const reg_t addr, csr_t_p mcountinhibit); + reg_t read() const noexcept override; + virtual void verify_permissions(insn_t insn, bool write) const override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +class mtopi_csr_t: public csr_t { + public: + mtopi_csr_t(processor_t* const proc, const reg_t addr); + virtual reg_t read() const noexcept override; + protected: + bool unlogged_write(const reg_t val) noexcept override; +}; + +class mvip_csr_t : public basic_csr_t { + public: + mvip_csr_t(processor_t* const proc, const reg_t addr, const reg_t init); + reg_t read() const noexcept override; + + void write_with_mask(const reg_t mask, const reg_t val) noexcept; + + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +typedef std::shared_ptr<mvip_csr_t> mvip_csr_t_p; + +class nonvirtual_stopi_csr_t: public csr_t { + public: + nonvirtual_stopi_csr_t(processor_t* const proc, const reg_t addr); + virtual void verify_permissions(insn_t insn, bool write) const override; + virtual reg_t read() const noexcept override; + protected: + bool unlogged_write(const reg_t val) noexcept override; +}; + +class inaccessible_csr_t: public csr_t { + public: + inaccessible_csr_t(processor_t* const proc, const reg_t addr); + virtual void verify_permissions(insn_t insn, bool write) const override; + reg_t read() const noexcept override { return 0; } + protected: + bool unlogged_write(const reg_t UNUSED val) noexcept override { return false; } +}; + +class vstopi_csr_t: public csr_t { + public: + vstopi_csr_t(processor_t* const proc, const reg_t addr); + virtual void verify_permissions(insn_t insn, bool write) const override; + virtual reg_t read() const noexcept override; + protected: + bool unlogged_write(const reg_t val) noexcept override; +}; + +class siselect_csr_t: public basic_csr_t { + public: + siselect_csr_t(processor_t* const proc, const reg_t addr, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class aia_csr_t: public masked_csr_t { + public: + aia_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; #endif diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 5d49605..a89a4ff 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -13,7 +13,7 @@ #if 0 # define D(x) x #else -# define D(x) +# define D(x) (void) 0 #endif // Return the number of bits wide that a field has to be to encode up to n @@ -249,6 +249,11 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } +reg_t debug_module_t::size() +{ + return PGSIZE; +} + void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value) { uint8_t* base = memory + index * 4; @@ -445,7 +450,6 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) } else { dmstatus.allresumeack = false; } - auto hart = sim->get_harts().at(hart_id); if (!hart_available(hart_id)) { dmstatus.allrunning = false; dmstatus.allhalted = false; @@ -462,9 +466,9 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) } } - // We don't allow selecting non-existant harts through + // We don't allow selecting non-existent harts through // hart_array_mask, so the only way it's possible is by writing a - // non-existant hartsel. + // non-existent hartsel. dmstatus.anynonexistant = dmcontrol.hartsel >= sim->get_cfg().nprocs(); result = set_field(result, DM_DMSTATUS_IMPEBREAK, diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 3771489..904f03e 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -114,8 +114,9 @@ class debug_module_t : public abstract_device_t debug_module_t(simif_t *sim, const debug_module_config_t &config); ~debug_module_t(); - bool load(reg_t addr, size_t len, uint8_t* bytes); - bool store(reg_t addr, size_t len, const uint8_t* bytes); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; // Debug Module Interface that the debugger (in our case through JTAG DTM) // uses to access the DM. diff --git a/riscv/decode.h b/riscv/decode.h index f36c04e..51ecbeb 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -79,6 +79,10 @@ public: insn_t(insn_bits_t bits) : b(bits) {} insn_bits_t bits() { return b; } int length() { return insn_length(b); } + [[maybe_unused]] int64_t opcode() { return x(0, 7); } + [[maybe_unused]] int64_t funct7() { return x(25, 7); } + [[maybe_unused]] int64_t funct3() { return x(12, 3); } + [[maybe_unused]] int64_t funct2() { return x(25, 2); } int64_t i_imm() { return xs(20, 12); } int64_t shamt() { return x(20, 6); } int64_t s_imm() { return x(7, 5) + (xs(25, 7) << 5); } @@ -95,6 +99,7 @@ public: uint64_t bs() { return x(30, 2); } // Crypto ISE - SM4/AES32 byte select. uint64_t rcon() { return x(20, 4); } // Crypto ISE - AES64 round const. + [[maybe_unused]] int64_t rvc_opcode() { return x(0, 2); } int64_t rvc_imm() { return x(2, 5) + (xs(12, 1) << 5); } int64_t rvc_zimm() { return x(2, 5) + (x(12, 1) << 5); } int64_t rvc_addi4spn_imm() { return (x(6, 1) << 2) + (x(5, 1) << 3) + (x(11, 2) << 4) + (x(7, 4) << 6); } @@ -170,23 +175,29 @@ public: switch (rvc_rlist()) { case 15: stack_adj_base += 16; + [[fallthrough]]; case 14: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 13: case 12: stack_adj_base += 16; + [[fallthrough]]; case 11: case 10: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 9: case 8: stack_adj_base += 16; + [[fallthrough]]; case 7: case 6: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 5: case 4: stack_adj_base += 16; diff --git a/riscv/decode_macros.h b/riscv/decode_macros.h index 675634a..892515f 100644 --- a/riscv/decode_macros.h +++ b/riscv/decode_macros.h @@ -22,6 +22,7 @@ #define RS2 READ_REG(insn.rs2()) #define RS3 READ_REG(insn.rs3()) #define WRITE_RD(value) WRITE_REG(insn.rd(), value) +#define CHECK_RD() CHECK_REG(insn.rd()) /* 0 : int * 1 : floating @@ -30,9 +31,9 @@ * 4 : csr */ #define WRITE_REG(reg, value) ({ \ + CHECK_REG(reg); \ reg_t wdata = (value); /* value may have side effects */ \ if (DECODE_MACRO_USAGE_LOGGED) STATE.log_reg_write[(reg) << 4] = {wdata, 0}; \ - CHECK_REG(reg); \ STATE.XPR.write(reg, wdata); \ }) #define WRITE_FREG(reg, value) ({ \ @@ -83,7 +84,7 @@ // Zilsd macros #define WRITE_RD_D(value) (xlen == 32 ? WRITE_RD_PAIR(value) : WRITE_RD(value)) -// Zcmlsd macros +// Zclsd macros #define WRITE_RVC_RS2S_PAIR(value) WRITE_REG_PAIR(insn.rvc_rs2s(), value) #define RVC_RS2S_PAIR READ_REG_PAIR(insn.rvc_rs2s()) #define RVC_RS2_PAIR READ_REG_PAIR(insn.rvc_rs2()) @@ -164,10 +165,9 @@ static inline bool is_aligned(const unsigned val, const unsigned pos) #define require_extension(s) require(p->extension_enabled(s)) #define require_either_extension(A,B) require(p->extension_enabled(A) || p->extension_enabled(B)); #define require_impl(s) require(p->supports_impl(s)) -#define require_fs require(STATE.sstatus->enabled(SSTATUS_FS)) #define require_fp STATE.fflags->verify_permissions(insn, false) #define require_accelerator require(STATE.sstatus->enabled(SSTATUS_XS)) -#define require_vector_vs require(STATE.sstatus->enabled(SSTATUS_VS)) +#define require_vector_vs require(p->any_vector_extensions() && STATE.sstatus->enabled(SSTATUS_VS)) #define require_vector(alu) \ do { \ require_vector_vs; \ @@ -211,15 +211,18 @@ static inline bool is_aligned(const unsigned val, const unsigned pos) } \ } while (0); -#define set_fp_exceptions ({ if (softfloat_exceptionFlags) { \ - STATE.fflags->write(STATE.fflags->read() | softfloat_exceptionFlags); \ - } \ - softfloat_exceptionFlags = 0; }) +#define raise_fp_exceptions(flags) do { if (flags) STATE.fflags->write(STATE.fflags->read() | (flags)); } while (0); +#define set_fp_exceptions \ + do { \ + raise_fp_exceptions(softfloat_exceptionFlags); \ + softfloat_exceptionFlags = 0; \ + } while (0); #define sext32(x) ((sreg_t)(int32_t)(x)) #define zext32(x) ((reg_t)(uint32_t)(x)) -#define sext_xlen(x) (((sreg_t)(x) << (64 - xlen)) >> (64 - xlen)) +#define sext(x, pos) (((sreg_t)(x) << (64 - (pos))) >> (64 - (pos))) #define zext(x, pos) (((reg_t)(x) << (64 - (pos))) >> (64 - (pos))) +#define sext_xlen(x) sext(x, xlen) #define zext_xlen(x) zext(x, xlen) #define set_pc(x) \ @@ -334,10 +337,10 @@ inline long double to_f(float128_t f) { long double r; memcpy(&r, &f, sizeof(r)) #define DEBUG_RVV_FMA_VF \ printf("vfma(%lu) vd=%f vs1=%f vs2=%f vd_old=%f\n", i, to_f(vd), to_f(rs1), to_f(vs2), to_f(vd_old)); #else -#define DEBUG_RVV_FP_VV 0 -#define DEBUG_RVV_FP_VF 0 -#define DEBUG_RVV_FMA_VV 0 -#define DEBUG_RVV_FMA_VF 0 +#define DEBUG_RVV_FP_VV (void) 0 +#define DEBUG_RVV_FP_VF (void) 0 +#define DEBUG_RVV_FMA_VV (void) 0 +#define DEBUG_RVV_FMA_VF (void) 0 #endif #define DECLARE_XENVCFG_VARS(field) \ diff --git a/riscv/devices.cc b/riscv/devices.cc index 2c06f78..b816ca1 100644 --- a/riscv/devices.cc +++ b/riscv/devices.cc @@ -8,53 +8,92 @@ mmio_device_map_t& mmio_device_map() return device_map; } +static auto empty_device = rom_device_t(std::vector<char>()); + +bus_t::bus_t() + : bus_t(&empty_device) +{ +} + +bus_t::bus_t(abstract_device_t* fallback) + : fallback(fallback) +{ +} + void bus_t::add_device(reg_t addr, abstract_device_t* dev) { - // Searching devices via lower_bound/upper_bound - // implicitly relies on the underlying std::map - // container to sort the keys and provide ordered - // iteration over this sort, which it does. (python's - // SortedDict is a good analogy) + // Allow empty devices by omitting them + auto size = dev->size(); + if (size == 0) + return; + + // Reject devices that overflow address size + if (addr + size - 1 < addr) { + fprintf(stderr, "device at [%" PRIx64 ", %" PRIx64 ") overflows address size\n", + addr, addr + size); + abort(); + } + + // Reject devices that overlap other devices + if (auto it = devices.upper_bound(addr); + (it != devices.end() && addr + size - 1 >= it->first) || + (it != devices.begin() && (it--, it->first + it->second->size() - 1 >= addr))) { + fprintf(stderr, "devices at [%" PRIx64 ", %" PRIx64 ") and [%" PRIx64 ", %" PRIx64 ") overlap\n", + it->first, it->first + it->second->size(), addr, addr + size); + abort(); + } + devices[addr] = dev; } bool bus_t::load(reg_t addr, size_t len, uint8_t* bytes) { - // Find the device with the base address closest to but - // less than addr (price-is-right search) - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - // Either the bus is empty, or there weren't - // any items with a base address <= addr - return false; - } - // Found at least one item with base address <= addr - // The iterator points to the device after this, so - // go back by one item. - it--; - return it->second->load(addr - it->first, len, bytes); + if (auto [base, dev] = find_device(addr, len); dev) + return dev->load(addr - base, len, bytes); + return false; } bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes) { - // See comments in bus_t::load - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - return false; - } - it--; - return it->second->store(addr - it->first, len, bytes); + if (auto [base, dev] = find_device(addr, len); dev) + return dev->store(addr - base, len, bytes); + return false; } -std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr) +reg_t bus_t::size() { - // See comments in bus_t::load - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - return std::make_pair((reg_t)0, (abstract_device_t*)NULL); + if (auto last = devices.rbegin(); last != devices.rend()) + return last->first + last->second->size(); + return 0; +} + +std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr, size_t len) +{ + if (unlikely(!len || addr + len - 1 < addr)) + return std::make_pair(0, nullptr); + + // Obtain iterator to device immediately after the one that might match + auto it_after = devices.upper_bound(addr); + reg_t base, size; + if (likely(it_after != devices.begin())) { + // Obtain iterator to device that might match + auto it = std::prev(it_after); + base = it->first; + size = it->second->size(); + if (likely(addr - base + len - 1 < size)) { + // it fully contains [addr, addr + len) + return std::make_pair(it->first, it->second); + } } - it--; - return std::make_pair(it->first, it->second); + + if (unlikely((it_after != devices.end() && addr + len - 1 >= it_after->first) + || (it_after != devices.begin() && addr - base < size))) { + // it_after or it contains part of, but not all of, [addr, add + len) + return std::make_pair(0, nullptr); + } + + // No matching device + return std::make_pair(0, fallback); } mem_t::mem_t(reg_t size) @@ -116,3 +155,25 @@ void mem_t::dump(std::ostream& o) { } } } + +external_sim_device_t::external_sim_device_t(abstract_sim_if_t* sim) + : external_simulator(sim) {} + +void external_sim_device_t::set_simulator(abstract_sim_if_t* sim) { + external_simulator = sim; +} + +bool external_sim_device_t::load(reg_t addr, size_t len, uint8_t* bytes) { + if (unlikely(external_simulator == nullptr)) return false; + return external_simulator->load(addr, len, bytes); +} + +bool external_sim_device_t::store(reg_t addr, size_t len, const uint8_t* bytes) { + if (unlikely(external_simulator == nullptr)) return false; + return external_simulator->store(addr, len, bytes); +} + +reg_t external_sim_device_t::size() { + if (unlikely(external_simulator == nullptr)) return 0; + return PGSIZE; // TODO: proper size +} diff --git a/riscv/devices.h b/riscv/devices.h index 6ef32e9..ccb5c9b 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -16,14 +16,21 @@ class simif_t; class bus_t : public abstract_device_t { public: + bus_t(); + + // the fallback device owns all addresses not owned by other devices + bus_t(abstract_device_t* fallback); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; void add_device(reg_t addr, abstract_device_t* dev); - std::pair<reg_t, abstract_device_t*> find_device(reg_t addr); + std::pair<reg_t, abstract_device_t*> find_device(reg_t addr, size_t len); private: std::map<reg_t, abstract_device_t*> devices; + abstract_device_t* fallback; }; class rom_device_t : public abstract_device_t { @@ -31,6 +38,7 @@ class rom_device_t : public abstract_device_t { rom_device_t(std::vector<char> data); bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override { return data.size(); } const std::vector<char>& contents() { return data; } private: std::vector<char> data; @@ -41,7 +49,6 @@ class abstract_mem_t : public abstract_device_t { virtual ~abstract_mem_t() = default; virtual char* contents(reg_t addr) = 0; - virtual reg_t size() = 0; virtual void dump(std::ostream& o) = 0; }; @@ -64,12 +71,31 @@ class mem_t : public abstract_mem_t { reg_t sz; }; +class abstract_sim_if_t { +public: + virtual ~abstract_sim_if_t() = default; + virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0; + virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0; +}; + +class external_sim_device_t : public abstract_device_t { +public: + external_sim_device_t(abstract_sim_if_t* sim); + void set_simulator(abstract_sim_if_t* sim); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; + +private: + abstract_sim_if_t* external_simulator; +}; + class clint_t : public abstract_device_t { public: clint_t(const simif_t*, uint64_t freq_hz, bool real_time); bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; - size_t size() { return CLINT_SIZE; } + reg_t size() override { return CLINT_SIZE; } void tick(reg_t rtc_ticks) override; uint64_t get_mtimecmp(reg_t hartid) { return mtimecmp[hartid]; } uint64_t get_mtime() { return mtime; } @@ -109,7 +135,7 @@ class plic_t : public abstract_device_t, public abstract_interrupt_controller_t bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; void set_interrupt_level(uint32_t id, int lvl) override; - size_t size() { return PLIC_SIZE; } + reg_t size() override { return PLIC_SIZE; } private: std::vector<plic_context_t> contexts; uint32_t num_ids; @@ -140,7 +166,7 @@ class ns16550_t : public abstract_device_t { bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; void tick(reg_t rtc_ticks) override; - size_t size() { return NS16550_SIZE; } + reg_t size() override { return NS16550_SIZE; } private: abstract_interrupt_controller_t *intctrl; uint32_t interrupt_id; diff --git a/riscv/disasm.h b/riscv/disasm.h index d4b8c2c..4a1ea42 100644 --- a/riscv/disasm.h +++ b/riscv/disasm.h @@ -82,7 +82,7 @@ class disasm_insn_t class disassembler_t { public: - disassembler_t(const isa_parser_t *isa); + disassembler_t(const isa_parser_t *isa, bool strict = false); ~disassembler_t(); std::string disassemble(insn_t insn) const; @@ -94,7 +94,7 @@ class disassembler_t static const int HASH_SIZE = 255; std::vector<const disasm_insn_t*> chain[HASH_SIZE+1]; - void add_instructions(const isa_parser_t* isa); + void add_instructions(const isa_parser_t* isa, bool strict); const disasm_insn_t* probe_once(insn_t insn, size_t idx) const; diff --git a/riscv/dts.cc b/riscv/dts.cc index 8304171..5be9d57 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -13,14 +13,17 @@ #include <sys/types.h> std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, - reg_t initrd_start, reg_t initrd_end, - const char* bootargs, - size_t pmpregions, - size_t pmpgranularity, - std::vector<processor_t*> procs, + const cfg_t* cfg, std::vector<std::pair<reg_t, abstract_mem_t*>> mems, std::string device_nodes) { + reg_t initrd_start = cfg->initrd_bounds.first; + reg_t initrd_end = cfg->initrd_bounds.second; + const char* bootargs = cfg->bootargs; + reg_t pmpregions = cfg->pmpregions; + reg_t pmpgranularity = cfg->pmpgranularity; + isa_parser_t isa(cfg->isa, cfg->priv); + std::stringstream s; s << std::dec << "/dts-v1/;\n" @@ -54,14 +57,14 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, " #address-cells = <1>;\n" " #size-cells = <0>;\n" " timebase-frequency = <" << (cpu_hz/insns_per_rtc_tick) << ">;\n"; - for (size_t i = 0; i < procs.size(); i++) { + for (size_t i = 0; i < cfg->nprocs(); i++) { s << " CPU" << i << ": cpu@" << i << " {\n" " device_type = \"cpu\";\n" - " reg = <" << i << ">;\n" + " reg = <" << cfg->hartids[i] << ">;\n" " status = \"okay\";\n" " compatible = \"riscv\";\n" - " riscv,isa = \"" << procs[i]->get_isa().get_isa_string() << "\";\n" - " mmu-type = \"riscv," << (procs[i]->get_isa().get_max_xlen() <= 32 ? "sv32" : "sv57") << "\";\n" + " riscv,isa = \"" << isa.get_isa_string() << "\";\n" + " mmu-type = \"riscv," << (isa.get_max_xlen() <= 32 ? "sv32" : "sv57") << "\";\n" " riscv,pmpregions = <" << pmpregions << ">;\n" " riscv,pmpgranularity = <" << pmpgranularity << ">;\n" " clock-frequency = <" << cpu_hz << ">;\n" @@ -96,86 +99,98 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, return s.str(); } -std::string dts_compile(const std::string& dts) +static std::string dtc_compile(const std::string& dtc_input, bool compile) { - // Convert the DTS to DTB - int dts_pipe[2]; - pid_t dts_pid; + const char* input_type = compile ? "dts" : "dtb"; + const char* output_type = compile ? "dtb" : "dts"; + + int dtc_input_pipe[2]; + pid_t dtc_input_pid; fflush(NULL); // flush stdout/stderr before forking - if (pipe(dts_pipe) != 0 || (dts_pid = fork()) < 0) { - std::cerr << "Failed to fork dts child: " << strerror(errno) << std::endl; + if (pipe(dtc_input_pipe) != 0 || (dtc_input_pid = fork()) < 0) { + std::cerr << "Failed to fork dtc_input child: " << strerror(errno) << std::endl; exit(1); } - // Child process to output dts - if (dts_pid == 0) { - close(dts_pipe[0]); - int step, len = dts.length(); - const char *buf = dts.c_str(); + // Child process to output dtc_input + if (dtc_input_pid == 0) { + close(dtc_input_pipe[0]); + int step, len = dtc_input.length(); + const char *buf = dtc_input.c_str(); for (int done = 0; done < len; done += step) { - step = write(dts_pipe[1], buf+done, len-done); + step = write(dtc_input_pipe[1], buf+done, len-done); if (step == -1) { - std::cerr << "Failed to write dts: " << strerror(errno) << std::endl; + std::cerr << "Failed to write dtc_input: " << strerror(errno) << std::endl; exit(1); } } - close(dts_pipe[1]); + close(dtc_input_pipe[1]); exit(0); } - pid_t dtb_pid; - int dtb_pipe[2]; - if (pipe(dtb_pipe) != 0 || (dtb_pid = fork()) < 0) { - std::cerr << "Failed to fork dtb child: " << strerror(errno) << std::endl; + pid_t dtc_output_pid; + int dtc_output_pipe[2]; + if (pipe(dtc_output_pipe) != 0 || (dtc_output_pid = fork()) < 0) { + std::cerr << "Failed to fork dtc_output child: " << strerror(errno) << std::endl; exit(1); } - // Child process to output dtb - if (dtb_pid == 0) { - dup2(dts_pipe[0], 0); - dup2(dtb_pipe[1], 1); - close(dts_pipe[0]); - close(dts_pipe[1]); - close(dtb_pipe[0]); - close(dtb_pipe[1]); - execlp(DTC, DTC, "-O", "dtb", (char *)0); + // Child process to output dtc_output + if (dtc_output_pid == 0) { + dup2(dtc_input_pipe[0], 0); + dup2(dtc_output_pipe[1], 1); + close(dtc_input_pipe[0]); + close(dtc_input_pipe[1]); + close(dtc_output_pipe[0]); + close(dtc_output_pipe[1]); + execlp(DTC, DTC, "-O", output_type, "-I", input_type, nullptr); std::cerr << "Failed to run " DTC ": " << strerror(errno) << std::endl; exit(1); } - close(dts_pipe[1]); - close(dts_pipe[0]); - close(dtb_pipe[1]); + close(dtc_input_pipe[1]); + close(dtc_input_pipe[0]); + close(dtc_output_pipe[1]); - // Read-out dtb - std::stringstream dtb; + // Read-out dtc_output + std::stringstream dtc_output; int got; char buf[4096]; - while ((got = read(dtb_pipe[0], buf, sizeof(buf))) > 0) { - dtb.write(buf, got); + while ((got = read(dtc_output_pipe[0], buf, sizeof(buf))) > 0) { + dtc_output.write(buf, got); } if (got == -1) { - std::cerr << "Failed to read dtb: " << strerror(errno) << std::endl; + std::cerr << "Failed to read dtc_output: " << strerror(errno) << std::endl; exit(1); } - close(dtb_pipe[0]); + close(dtc_output_pipe[0]); // Reap children int status; - waitpid(dts_pid, &status, 0); + waitpid(dtc_input_pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - std::cerr << "Child dts process failed" << std::endl; + std::cerr << "Child dtc_input process failed" << std::endl; exit(1); } - waitpid(dtb_pid, &status, 0); + waitpid(dtc_output_pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - std::cerr << "Child dtb process failed" << std::endl; + std::cerr << "Child dtc_output process failed" << std::endl; exit(1); } - return dtb.str(); + return dtc_output.str(); +} + +std::string dtb_to_dts(const std::string& dtc_input) +{ + return dtc_compile(dtc_input, false); +} + +std::string dts_to_dtb(const std::string& dtc_input) +{ + return dtc_compile(dtc_input, true); } int fdt_get_node_addr_size(const void *fdt, int node, reg_t *addr, @@ -386,3 +401,43 @@ int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type) return 0; } + +int fdt_parse_isa(const void *fdt, int cpu_offset, const char **isa) +{ + assert(isa); + + int len, rc; + const void *prop; + + if ((rc = check_cpu_node(fdt, cpu_offset)) < 0) + return rc; + + prop = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len); + if (!prop || !len) + return -EINVAL; + + *isa = (const char *)prop; + + return 0; +} + +int fdt_parse_hartid(const void *fdt, int cpu_offset, uint32_t *hartid) +{ + int len, rc; + const fdt32_t *val; + + if ((rc = check_cpu_node(fdt, cpu_offset)) < 0) + return rc; + + val = (fdt32_t*) fdt_getprop(fdt, cpu_offset, "reg", &len); + if (!val || len < (int) sizeof(fdt32_t)) + return -EINVAL; + + if (len > (int) sizeof(fdt32_t)) + val++; + + if (hartid) + *hartid = fdt32_to_cpu(*val); + + return 0; +} diff --git a/riscv/dts.h b/riscv/dts.h index 7afe376..730dea7 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -7,15 +7,12 @@ #include <string> std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, - reg_t initrd_start, reg_t initrd_end, - const char* bootargs, - size_t pmpregions, - size_t pmpgranularity, - std::vector<processor_t*> procs, + const cfg_t* cfg, std::vector<std::pair<reg_t, abstract_mem_t*>> mems, std::string device_nodes); -std::string dts_compile(const std::string& dts); +std::string dts_to_dtb(const std::string& dtc_input); +std::string dtb_to_dts(const std::string& dtc_input); int fdt_get_node_addr_size(const void *fdt, int node, reg_t *addr, unsigned long *size, const char *field); @@ -33,4 +30,6 @@ int fdt_parse_ns16550(const void *fdt, reg_t *ns16550_addr, int fdt_parse_pmp_num(const void *fdt, int cpu_offset, reg_t *pmp_num); int fdt_parse_pmp_alignment(const void *fdt, int cpu_offset, reg_t *pmp_align); int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type); +int fdt_parse_isa(const void *fdt, int cpu_offset, const char **isa_str); +int fdt_parse_hartid(const void *fdt, int cpu_offset, uint32_t *hartid); #endif diff --git a/riscv/encoding.h b/riscv/encoding.h index 4b2e0b6..bcc1ace 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -4,7 +4,7 @@ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (7bed351) + * https://github.com/riscv/riscv-opcodes (8899b32) */ #ifndef RISCV_CSR_ENCODING_H @@ -30,6 +30,7 @@ #define MSTATUS_TW 0x00200000 #define MSTATUS_TSR 0x00400000 #define MSTATUS_SPELP 0x00800000 +#define MSTATUS_SDT 0x01000000 #define MSTATUS32_SD 0x80000000 #define MSTATUS_UXL 0x0000000300000000 #define MSTATUS_SXL 0x0000000C00000000 @@ -38,12 +39,14 @@ #define MSTATUS_GVA 0x0000004000000000 #define MSTATUS_MPV 0x0000008000000000 #define MSTATUS_MPELP 0x0000020000000000 +#define MSTATUS_MDT 0x0000040000000000 #define MSTATUS64_SD 0x8000000000000000 #define MSTATUSH_SBE 0x00000010 #define MSTATUSH_MBE 0x00000020 #define MSTATUSH_GVA 0x00000040 #define MSTATUSH_MPV 0x00000080 +#define MSTATUSH_MDT 0x00000400 #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 @@ -57,6 +60,7 @@ #define SSTATUS_SUM 0x00040000 #define SSTATUS_MXR 0x00080000 #define SSTATUS_SPELP 0x00800000 +#define SSTATUS_SDT 0x01000000 #define SSTATUS32_SD 0x80000000 #define SSTATUS_UXL 0x0000000300000000 #define SSTATUS64_SD 0x8000000000000000 @@ -71,27 +75,32 @@ #define HSTATUS_SPV 0x00000080 #define HSTATUS_GVA 0x00000040 #define HSTATUS_VSBE 0x00000020 +#define HSTATUS_HUPMM 0x0003000000000000 #define USTATUS_UIE 0x00000001 #define USTATUS_UPIE 0x00000010 #define MNSTATUS_NMIE 0x00000008 -#define MNSTATUS_MNPP 0x00001800 #define MNSTATUS_MNPV 0x00000080 +#define MNSTATUS_MNPELP 0x00000200 +#define MNSTATUS_MNPP 0x00001800 -#define DCSR_XDEBUGVER (3U<<30) -#define DCSR_NDRESET (1<<29) -#define DCSR_FULLRESET (1<<28) +#define DCSR_XDEBUGVER (15U<<28) +#define DCSR_EXTCAUSE (7<<24) +#define DCSR_CETRIG (1<<19) #define DCSR_PELP (1<<18) +#define DCSR_EBREAKVS (1<<17) +#define DCSR_EBREAKVU (1<<16) #define DCSR_EBREAKM (1<<15) -#define DCSR_EBREAKH (1<<14) #define DCSR_EBREAKS (1<<13) #define DCSR_EBREAKU (1<<12) -#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STEPIE (1<<11) +#define DCSR_STOPCOUNT (1<<10) #define DCSR_STOPTIME (1<<9) #define DCSR_CAUSE (7<<6) -#define DCSR_DEBUGINT (1<<5) -#define DCSR_HALT (1<<3) +#define DCSR_V (1<<5) +#define DCSR_MPRVEN (1<<4) +#define DCSR_NMIP (1<<3) #define DCSR_STEP (1<<2) #define DCSR_PRV (3<<0) @@ -102,6 +111,9 @@ #define DCSR_CAUSE_STEP 4 #define DCSR_CAUSE_HALT 5 #define DCSR_CAUSE_GROUP 6 +#define DCSR_CAUSE_EXTCAUSE 7 + +#define DCSR_EXTCAUSE_CRITERR 0 #define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) #define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) @@ -109,7 +121,7 @@ #define MCONTROL_SELECT (1<<19) #define MCONTROL_TIMING (1<<18) -#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_ACTION (0xf<<12) #define MCONTROL_CHAIN (1<<11) #define MCONTROL_MATCH (0xf<<7) #define MCONTROL_M (1<<6) @@ -168,10 +180,15 @@ #define MENVCFG_CBIE 0x00000030 #define MENVCFG_CBCFE 0x00000040 #define MENVCFG_CBZE 0x00000080 +#define MENVCFG_PMM 0x0000000300000000 +#define MENVCFG_DTE 0x0800000000000000 +#define MENVCFG_CDE 0x1000000000000000 #define MENVCFG_ADUE 0x2000000000000000 #define MENVCFG_PBMTE 0x4000000000000000 #define MENVCFG_STCE 0x8000000000000000 +#define MENVCFGH_DTE 0x08000000 +#define MENVCFGH_CDE 0x10000000 #define MENVCFGH_ADUE 0x20000000 #define MENVCFGH_PBMTE 0x40000000 #define MENVCFGH_STCE 0x80000000 @@ -179,6 +196,8 @@ #define MSTATEEN0_CS 0x00000001 #define MSTATEEN0_FCSR 0x00000002 #define MSTATEEN0_JVT 0x00000004 +#define MSTATEEN0_CTR 0x0040000000000000 +#define MSTATEEN0_PRIV113 0x0100000000000000 #define MSTATEEN0_PRIV114 0x0080000000000000 #define MSTATEEN0_HCONTEXT 0x0200000000000000 #define MSTATEEN0_AIA 0x0800000000000000 @@ -186,6 +205,8 @@ #define MSTATEEN0_HENVCFG 0x4000000000000000 #define MSTATEEN_HSTATEEN 0x8000000000000000 +#define MSTATEEN0H_CTR 0x00400000 +#define MSTATEEN0H_PRIV113 0x01000000 #define MSTATEEN0H_PRIV114 0x00800000 #define MSTATEEN0H_HCONTEXT 0x02000000 #define MSTATEEN0H_AIA 0x08000000 @@ -207,16 +228,30 @@ #define MHPMEVENTH_MINH 0x40000000 #define MHPMEVENTH_OF 0x80000000 +#define MCOUNTEREN_CY_SHIFT 0 +#define MCOUNTEREN_TIME_SHIFT 1 +#define MCOUNTEREN_IR_SHIFT 2 + +#define MCOUNTEREN_CY (1U << MCOUNTEREN_CY_SHIFT) +#define MCOUNTEREN_TIME (1U << MCOUNTEREN_TIME_SHIFT) +#define MCOUNTEREN_IR (1U << MCOUNTEREN_IR_SHIFT) + +#define MCOUNTINHIBIT_CY MCOUNTEREN_CY +#define MCOUNTINHIBIT_IR MCOUNTEREN_IR + #define HENVCFG_FIOM 0x00000001 #define HENVCFG_LPE 0x00000004 #define HENVCFG_SSE 0x00000008 #define HENVCFG_CBIE 0x00000030 #define HENVCFG_CBCFE 0x00000040 #define HENVCFG_CBZE 0x00000080 +#define HENVCFG_PMM 0x0000000300000000 +#define HENVCFG_DTE 0x0800000000000000 #define HENVCFG_ADUE 0x2000000000000000 #define HENVCFG_PBMTE 0x4000000000000000 #define HENVCFG_STCE 0x8000000000000000 +#define HENVCFGH_DTE 0x08000000 #define HENVCFGH_ADUE 0x20000000 #define HENVCFGH_PBMTE 0x40000000 #define HENVCFGH_STCE 0x80000000 @@ -236,12 +271,14 @@ #define HSTATEEN0_CS 0x00000001 #define HSTATEEN0_FCSR 0x00000002 #define HSTATEEN0_JVT 0x00000004 +#define HSTATEEN0_CTR 0x0040000000000000 #define HSTATEEN0_SCONTEXT 0x0200000000000000 #define HSTATEEN0_AIA 0x0800000000000000 #define HSTATEEN0_CSRIND 0x1000000000000000 #define HSTATEEN0_SENVCFG 0x4000000000000000 #define HSTATEEN_SSTATEEN 0x8000000000000000 +#define HSTATEEN0H_CTR 0x00400000 #define HSTATEEN0H_SCONTEXT 0x02000000 #define HSTATEEN0H_AIA 0x08000000 #define HSTATEEN0H_CSRIND 0x10000000 @@ -254,6 +291,7 @@ #define SENVCFG_CBIE 0x00000030 #define SENVCFG_CBCFE 0x00000040 #define SENVCFG_CBZE 0x00000080 +#define SENVCFG_PMM 0x0000000300000000 #define SSTATEEN0_CS 0x00000001 #define SSTATEEN0_FCSR 0x00000002 @@ -265,6 +303,7 @@ #define MSECCFG_USEED 0x00000100 #define MSECCFG_SSEED 0x00000200 #define MSECCFG_MLPE 0x00000400 +#define MSECCFG_PMM 0x0000000300000000 /* jvt fields */ #define JVT_MODE 0x3F @@ -324,6 +363,73 @@ #define PMP_NA4 0x10 #define PMP_NAPOT 0x18 +#define MCTRCTL_U 0x0000000000000001 +#define MCTRCTL_S 0x0000000000000002 +#define MCTRCTL_M 0x0000000000000004 +#define MCTRCTL_RASEMU 0x0000000000000080 +#define MCTRCTL_STE 0x0000000000000100 +#define MCTRCTL_MTE 0x0000000000000200 +#define MCTRCTL_BPFRZ 0x0000000000000800 +#define MCTRCTL_LCOFIFRZ 0x0000000000001000 +#define MCTRCTL_EXCINH 0x0000000200000000 +#define MCTRCTL_INTRINH 0x0000000400000000 +#define MCTRCTL_TRETINH 0x0000000800000000 +#define MCTRCTL_NTBREN 0x0000001000000000 +#define MCTRCTL_TKBRINH 0x0000002000000000 +#define MCTRCTL_INDCALLINH 0x0000010000000000 +#define MCTRCTL_DIRCALLINH 0x0000020000000000 +#define MCTRCTL_INDJMPINH 0x0000040000000000 +#define MCTRCTL_DIRJMPINH 0x0000080000000000 +#define MCTRCTL_CORSWAPINH 0x0000100000000000 +#define MCTRCTL_RETINH 0x0000200000000000 +#define MCTRCTL_INDLJMPINH 0x0000400000000000 +#define MCTRCTL_DIRLJMPINH 0x0000800000000000 + +#define SCTRCTL_U 0x0000000000000001 +#define SCTRCTL_S 0x0000000000000002 +#define SCTRCTL_RASEMU 0x0000000000000080 +#define SCTRCTL_STE 0x0000000000000100 +#define SCTRCTL_BPFRZ 0x0000000000000800 +#define SCTRCTL_LCOFIFRZ 0x0000000000001000 +#define SCTRCTL_EXCINH 0x0000000200000000 +#define SCTRCTL_INTRINH 0x0000000400000000 +#define SCTRCTL_TRETINH 0x0000000800000000 +#define SCTRCTL_NTBREN 0x0000001000000000 +#define SCTRCTL_TKBRINH 0x0000002000000000 +#define SCTRCTL_INDCALLINH 0x0000010000000000 +#define SCTRCTL_DIRCALLINH 0x0000020000000000 +#define SCTRCTL_INDJMPINH 0x0000040000000000 +#define SCTRCTL_DIRJMPINH 0x0000080000000000 +#define SCTRCTL_CORSWAPINH 0x0000100000000000 +#define SCTRCTL_RETINH 0x0000200000000000 +#define SCTRCTL_INDLJMPINH 0x0000400000000000 +#define SCTRCTL_DIRLJMPINH 0x0000800000000000 + +#define VSCTRCTL_U 0x0000000000000001 +#define VSCTRCTL_S 0x0000000000000002 +#define VSCTRCTL_RASEMU 0x0000000000000080 +#define VSCTRCTL_STE 0x0000000000000100 +#define VSCTRCTL_BPFRZ 0x0000000000000800 +#define VSCTRCTL_LCOFIFRZ 0x0000000000001000 +#define VSCTRCTL_EXCINH 0x0000000200000000 +#define VSCTRCTL_INTRINH 0x0000000400000000 +#define VSCTRCTL_TRETINH 0x0000000800000000 +#define VSCTRCTL_NTBREN 0x0000001000000000 +#define VSCTRCTL_TKBRINH 0x0000002000000000 +#define VSCTRCTL_INDCALLINH 0x0000010000000000 +#define VSCTRCTL_DIRCALLINH 0x0000020000000000 +#define VSCTRCTL_INDJMPINH 0x0000040000000000 +#define VSCTRCTL_DIRJMPINH 0x0000080000000000 +#define VSCTRCTL_CORSWAPINH 0x0000100000000000 +#define VSCTRCTL_RETINH 0x0000200000000000 +#define VSCTRCTL_INDLJMPINH 0x0000400000000000 +#define VSCTRCTL_DIRLJMPINH 0x0000800000000000 + +#define SCTRDEPTH_DEPTH 0x00000007 + +#define SCTRSTATUS_WRPTR 0x000000FF +#define SCTRSTATUS_FROZEN 0x80000000 + #define IRQ_U_SOFT 0 #define IRQ_S_SOFT 1 #define IRQ_VS_SOFT 2 @@ -425,8 +531,6 @@ #define RISCV_ENCODING_H #define MATCH_ADD 0x33 #define MASK_ADD 0xfe00707f -#define MATCH_ADD64 0xc0001077 -#define MASK_ADD64 0xfe00707f #define MATCH_ADD_UW 0x800003b #define MASK_ADD_UW 0xfe00707f #define MATCH_ADDI 0x13 @@ -1151,14 +1255,6 @@ #define MASK_JAL 0x7f #define MATCH_JALR 0x67 #define MASK_JALR 0x707f -#define MATCH_KADD64 0x90001077 -#define MASK_KADD64 0xfe00707f -#define MATCH_KMAR64 0x94001077 -#define MASK_KMAR64 0xfe00707f -#define MATCH_KMSR64 0x96001077 -#define MASK_KMSR64 0xfe00707f -#define MATCH_KSUB64 0x92001077 -#define MASK_KSUB64 0xfe00707f #define MATCH_LB 0x3 #define MASK_LB 0x707f #define MATCH_LB_AQ 0x3400002f @@ -1293,10 +1389,6 @@ #define MASK_MULHSU 0xfe00707f #define MATCH_MULHU 0x2003033 #define MASK_MULHU 0xfe00707f -#define MATCH_MULR64 0xf0001077 -#define MASK_MULR64 0xfe00707f -#define MATCH_MULSR64 0xe0001077 -#define MASK_MULSR64 0xfe00707f #define MATCH_MULW 0x200003b #define MASK_MULW 0xfe00707f #define MATCH_OR 0x6033 @@ -1319,8 +1411,6 @@ #define MASK_PREFETCH_R 0x1f07fff #define MATCH_PREFETCH_W 0x306013 #define MASK_PREFETCH_W 0x1f07fff -#define MATCH_RADD64 0x80001077 -#define MASK_RADD64 0xfe00707f #define MATCH_REM 0x2006033 #define MASK_REM 0xfe00707f #define MATCH_REMU 0x2007033 @@ -1341,8 +1431,6 @@ #define MASK_RORIW 0xfe00707f #define MATCH_RORW 0x6000503b #define MASK_RORW 0xfe00707f -#define MATCH_RSUB64 0x82001077 -#define MASK_RSUB64 0xfe00707f #define MATCH_SB 0x23 #define MASK_SB 0x707f #define MATCH_SB_RL 0x3a00002f @@ -1351,6 +1439,8 @@ #define MASK_SC_D 0xf800707f #define MATCH_SC_W 0x1800202f #define MASK_SC_W 0xf800707f +#define MATCH_SCTRCLR 0x10400073 +#define MASK_SCTRCLR 0xffffffff #define MATCH_SD 0x3023 #define MASK_SD 0x707f #define MATCH_SD_RL 0x3a00302f @@ -1425,14 +1515,6 @@ #define MASK_SLLIW 0xfe00707f #define MATCH_SLLW 0x103b #define MASK_SLLW 0xfe00707f -#define MATCH_SLO 0x20001033 -#define MASK_SLO 0xfe00707f -#define MATCH_SLOI 0x20001013 -#define MASK_SLOI 0xfc00707f -#define MATCH_SLOIW 0x2000101b -#define MASK_SLOIW 0xfe00707f -#define MATCH_SLOW 0x2000103b -#define MASK_SLOW 0xfe00707f #define MATCH_SLT 0x2033 #define MASK_SLT 0xfe00707f #define MATCH_SLTI 0x2013 @@ -1449,40 +1531,6 @@ #define MASK_SM4ED 0x3e00707f #define MATCH_SM4KS 0x34000033 #define MASK_SM4KS 0x3e00707f -#define MATCH_SMAL 0x5e001077 -#define MASK_SMAL 0xfe00707f -#define MATCH_SMALBB 0x88001077 -#define MASK_SMALBB 0xfe00707f -#define MATCH_SMALBT 0x98001077 -#define MASK_SMALBT 0xfe00707f -#define MATCH_SMALDA 0x8c001077 -#define MASK_SMALDA 0xfe00707f -#define MATCH_SMALDRS 0x9a001077 -#define MASK_SMALDRS 0xfe00707f -#define MATCH_SMALDS 0x8a001077 -#define MASK_SMALDS 0xfe00707f -#define MATCH_SMALTT 0xa8001077 -#define MASK_SMALTT 0xfe00707f -#define MATCH_SMALXDA 0x9c001077 -#define MASK_SMALXDA 0xfe00707f -#define MATCH_SMALXDS 0xaa001077 -#define MASK_SMALXDS 0xfe00707f -#define MATCH_SMAR64 0x84001077 -#define MASK_SMAR64 0xfe00707f -#define MATCH_SMSLDA 0xac001077 -#define MASK_SMSLDA 0xfe00707f -#define MATCH_SMSLXDA 0xbc001077 -#define MASK_SMSLXDA 0xfe00707f -#define MATCH_SMSR64 0x86001077 -#define MASK_SMSR64 0xfe00707f -#define MATCH_SMUL16 0xa0000077 -#define MASK_SMUL16 0xfe00707f -#define MATCH_SMUL8 0xa8000077 -#define MASK_SMUL8 0xfe00707f -#define MATCH_SMULX16 0xa2000077 -#define MASK_SMULX16 0xfe00707f -#define MATCH_SMULX8 0xaa000077 -#define MASK_SMULX8 0xfe00707f #define MATCH_SRA 0x40005033 #define MASK_SRA 0xfe00707f #define MATCH_SRAI 0x40005013 @@ -1505,14 +1553,6 @@ #define MASK_SRLIW 0xfe00707f #define MATCH_SRLW 0x503b #define MASK_SRLW 0xfe00707f -#define MATCH_SRO 0x20005033 -#define MASK_SRO 0xfe00707f -#define MATCH_SROI 0x20005013 -#define MASK_SROI 0xfc00707f -#define MATCH_SROIW 0x2000501b -#define MASK_SROIW 0xfe00707f -#define MATCH_SROW 0x2000503b -#define MASK_SROW 0xfe00707f #define MATCH_SSAMOSWAP_D 0x4800302f #define MASK_SSAMOSWAP_D 0xf800707f #define MATCH_SSAMOSWAP_W 0x4800202f @@ -1529,40 +1569,14 @@ #define MASK_SSRDP 0xfffff07f #define MATCH_SUB 0x40000033 #define MASK_SUB 0xfe00707f -#define MATCH_SUB64 0xc2001077 -#define MASK_SUB64 0xfe00707f #define MATCH_SUBW 0x4000003b #define MASK_SUBW 0xfe00707f #define MATCH_SW 0x2023 #define MASK_SW 0x707f #define MATCH_SW_RL 0x3a00202f #define MASK_SW_RL 0xfa007fff -#define MATCH_UKADD64 0xb0001077 -#define MASK_UKADD64 0xfe00707f -#define MATCH_UKMAR64 0xb4001077 -#define MASK_UKMAR64 0xfe00707f -#define MATCH_UKMSR64 0xb6001077 -#define MASK_UKMSR64 0xfe00707f -#define MATCH_UKSUB64 0xb2001077 -#define MASK_UKSUB64 0xfe00707f -#define MATCH_UMAR64 0xa4001077 -#define MASK_UMAR64 0xfe00707f -#define MATCH_UMSR64 0xa6001077 -#define MASK_UMSR64 0xfe00707f -#define MATCH_UMUL16 0xb0000077 -#define MASK_UMUL16 0xfe00707f -#define MATCH_UMUL8 0xb8000077 -#define MASK_UMUL8 0xfe00707f -#define MATCH_UMULX16 0xb2000077 -#define MASK_UMULX16 0xfe00707f -#define MATCH_UMULX8 0xba000077 -#define MASK_UMULX8 0xfe00707f #define MATCH_UNSHFLI 0x8005013 #define MASK_UNSHFLI 0xfe00707f -#define MATCH_URADD64 0xa0001077 -#define MASK_URADD64 0xfe00707f -#define MATCH_URSUB64 0xa2001077 -#define MASK_URSUB64 0xfe00707f #define MATCH_VAADD_VV 0x24002057 #define MASK_VAADD_VV 0xfc00707f #define MATCH_VAADD_VX 0x24006057 @@ -2131,6 +2145,20 @@ #define MASK_VOR_VV 0xfc00707f #define MATCH_VOR_VX 0x28004057 #define MASK_VOR_VX 0xfc00707f +#define MATCH_VQDOT_VV 0xb0002057 +#define MASK_VQDOT_VV 0xfc00707f +#define MATCH_VQDOT_VX 0xb0006057 +#define MASK_VQDOT_VX 0xfc00707f +#define MATCH_VQDOTSU_VV 0xa8002057 +#define MASK_VQDOTSU_VV 0xfc00707f +#define MATCH_VQDOTSU_VX 0xa8006057 +#define MASK_VQDOTSU_VX 0xfc00707f +#define MATCH_VQDOTU_VV 0xa0002057 +#define MASK_VQDOTU_VV 0xfc00707f +#define MATCH_VQDOTU_VX 0xa0006057 +#define MASK_VQDOTU_VX 0xfc00707f +#define MATCH_VQDOTUS_VX 0xb8006057 +#define MASK_VQDOTUS_VX 0xfc00707f #define MATCH_VREDAND_VS 0x4002057 #define MASK_VREDAND_VS 0xfc00707f #define MATCH_VREDMAX_VS 0x1c002057 @@ -2487,6 +2515,8 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 #define CSR_STIMECMP 0x14d +#define CSR_SCTRCTL 0x14e +#define CSR_SCTRSTATUS 0x14f #define CSR_SISELECT 0x150 #define CSR_SIREG 0x151 #define CSR_SIREG2 0x152 @@ -2495,6 +2525,7 @@ #define CSR_SIREG5 0x156 #define CSR_SIREG6 0x157 #define CSR_STOPEI 0x15c +#define CSR_SCTRDEPTH 0x15f #define CSR_SATP 0x180 #define CSR_SRMCFG 0x181 #define CSR_SCONTEXT 0x5a8 @@ -2507,6 +2538,7 @@ #define CSR_VSTVAL 0x243 #define CSR_VSIP 0x244 #define CSR_VSTIMECMP 0x24d +#define CSR_VSCTRCTL 0x24e #define CSR_VSISELECT 0x250 #define CSR_VSIREG 0x251 #define CSR_VSIREG2 0x252 @@ -2579,6 +2611,7 @@ #define CSR_MIP 0x344 #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b +#define CSR_MCTRCTL 0x34e #define CSR_MISELECT 0x350 #define CSR_MIREG 0x351 #define CSR_MIREG2 0x352 @@ -2754,6 +2787,7 @@ #define CSR_VSIEH 0x214 #define CSR_VSIPH 0x254 #define CSR_VSTIMECMPH 0x25d +#define CSR_HEDELEGH 0x612 #define CSR_HTIMEDELTAH 0x615 #define CSR_HIDELEGH 0x613 #define CSR_HVIENH 0x618 @@ -2891,6 +2925,7 @@ #define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_STORE_PAGE_FAULT 0xf +#define CAUSE_DOUBLE_TRAP 0x10 #define CAUSE_SOFTWARE_CHECK_FAULT 0x12 #define CAUSE_HARDWARE_ERROR_FAULT 0x13 #define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 @@ -3004,10 +3039,10 @@ #define INSN_FIELD_MOP_RR_T_30 0x40000000 #define INSN_FIELD_MOP_RR_T_27_26 0xc000000 #define INSN_FIELD_C_MOP_T 0x700 +#define INSN_FIELD_RS2_EQ_RS1 0x1f00000 #endif #ifdef DECLARE_INSN DECLARE_INSN(add, MATCH_ADD, MASK_ADD) -DECLARE_INSN(add64, MATCH_ADD64, MASK_ADD64) DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) @@ -3370,10 +3405,6 @@ DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) -DECLARE_INSN(kadd64, MATCH_KADD64, MASK_KADD64) -DECLARE_INSN(kmar64, MATCH_KMAR64, MASK_KMAR64) -DECLARE_INSN(kmsr64, MATCH_KMSR64, MASK_KMSR64) -DECLARE_INSN(ksub64, MATCH_KSUB64, MASK_KSUB64) DECLARE_INSN(lb, MATCH_LB, MASK_LB) DECLARE_INSN(lb_aq, MATCH_LB_AQ, MASK_LB_AQ) DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) @@ -3441,8 +3472,6 @@ DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) -DECLARE_INSN(mulr64, MATCH_MULR64, MASK_MULR64) -DECLARE_INSN(mulsr64, MATCH_MULSR64, MASK_MULSR64) DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) DECLARE_INSN(or, MATCH_OR, MASK_OR) DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) @@ -3454,7 +3483,6 @@ DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) DECLARE_INSN(prefetch_i, MATCH_PREFETCH_I, MASK_PREFETCH_I) DECLARE_INSN(prefetch_r, MATCH_PREFETCH_R, MASK_PREFETCH_R) DECLARE_INSN(prefetch_w, MATCH_PREFETCH_W, MASK_PREFETCH_W) -DECLARE_INSN(radd64, MATCH_RADD64, MASK_RADD64) DECLARE_INSN(rem, MATCH_REM, MASK_REM) DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) @@ -3465,11 +3493,11 @@ DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) -DECLARE_INSN(rsub64, MATCH_RSUB64, MASK_RSUB64) DECLARE_INSN(sb, MATCH_SB, MASK_SB) DECLARE_INSN(sb_rl, MATCH_SB_RL, MASK_SB_RL) DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(sctrclr, MATCH_SCTRCLR, MASK_SCTRCLR) DECLARE_INSN(sd, MATCH_SD, MASK_SD) DECLARE_INSN(sd_rl, MATCH_SD_RL, MASK_SD_RL) DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) @@ -3507,10 +3535,6 @@ DECLARE_INSN(slli_rv32, MATCH_SLLI_RV32, MASK_SLLI_RV32) DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) -DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) -DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) -DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) -DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) @@ -3519,23 +3543,6 @@ DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) -DECLARE_INSN(smal, MATCH_SMAL, MASK_SMAL) -DECLARE_INSN(smalbb, MATCH_SMALBB, MASK_SMALBB) -DECLARE_INSN(smalbt, MATCH_SMALBT, MASK_SMALBT) -DECLARE_INSN(smalda, MATCH_SMALDA, MASK_SMALDA) -DECLARE_INSN(smaldrs, MATCH_SMALDRS, MASK_SMALDRS) -DECLARE_INSN(smalds, MATCH_SMALDS, MASK_SMALDS) -DECLARE_INSN(smaltt, MATCH_SMALTT, MASK_SMALTT) -DECLARE_INSN(smalxda, MATCH_SMALXDA, MASK_SMALXDA) -DECLARE_INSN(smalxds, MATCH_SMALXDS, MASK_SMALXDS) -DECLARE_INSN(smar64, MATCH_SMAR64, MASK_SMAR64) -DECLARE_INSN(smslda, MATCH_SMSLDA, MASK_SMSLDA) -DECLARE_INSN(smslxda, MATCH_SMSLXDA, MASK_SMSLXDA) -DECLARE_INSN(smsr64, MATCH_SMSR64, MASK_SMSR64) -DECLARE_INSN(smul16, MATCH_SMUL16, MASK_SMUL16) -DECLARE_INSN(smul8, MATCH_SMUL8, MASK_SMUL8) -DECLARE_INSN(smulx16, MATCH_SMULX16, MASK_SMULX16) -DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(srai_rv32, MATCH_SRAI_RV32, MASK_SRAI_RV32) @@ -3547,10 +3554,6 @@ DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srli_rv32, MATCH_SRLI_RV32, MASK_SRLI_RV32) DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) -DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) -DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) -DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) -DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) DECLARE_INSN(ssamoswap_d, MATCH_SSAMOSWAP_D, MASK_SSAMOSWAP_D) DECLARE_INSN(ssamoswap_w, MATCH_SSAMOSWAP_W, MASK_SSAMOSWAP_W) DECLARE_INSN(sspopchk_x1, MATCH_SSPOPCHK_X1, MASK_SSPOPCHK_X1) @@ -3559,23 +3562,10 @@ DECLARE_INSN(sspush_x1, MATCH_SSPUSH_X1, MASK_SSPUSH_X1) DECLARE_INSN(sspush_x5, MATCH_SSPUSH_X5, MASK_SSPUSH_X5) DECLARE_INSN(ssrdp, MATCH_SSRDP, MASK_SSRDP) DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) -DECLARE_INSN(sub64, MATCH_SUB64, MASK_SUB64) DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sw, MATCH_SW, MASK_SW) DECLARE_INSN(sw_rl, MATCH_SW_RL, MASK_SW_RL) -DECLARE_INSN(ukadd64, MATCH_UKADD64, MASK_UKADD64) -DECLARE_INSN(ukmar64, MATCH_UKMAR64, MASK_UKMAR64) -DECLARE_INSN(ukmsr64, MATCH_UKMSR64, MASK_UKMSR64) -DECLARE_INSN(uksub64, MATCH_UKSUB64, MASK_UKSUB64) -DECLARE_INSN(umar64, MATCH_UMAR64, MASK_UMAR64) -DECLARE_INSN(umsr64, MATCH_UMSR64, MASK_UMSR64) -DECLARE_INSN(umul16, MATCH_UMUL16, MASK_UMUL16) -DECLARE_INSN(umul8, MATCH_UMUL8, MASK_UMUL8) -DECLARE_INSN(umulx16, MATCH_UMULX16, MASK_UMULX16) -DECLARE_INSN(umulx8, MATCH_UMULX8, MASK_UMULX8) DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) -DECLARE_INSN(uradd64, MATCH_URADD64, MASK_URADD64) -DECLARE_INSN(ursub64, MATCH_URSUB64, MASK_URSUB64) DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) @@ -3860,6 +3850,13 @@ DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) +DECLARE_INSN(vqdot_vv, MATCH_VQDOT_VV, MASK_VQDOT_VV) +DECLARE_INSN(vqdot_vx, MATCH_VQDOT_VX, MASK_VQDOT_VX) +DECLARE_INSN(vqdotsu_vv, MATCH_VQDOTSU_VV, MASK_VQDOTSU_VV) +DECLARE_INSN(vqdotsu_vx, MATCH_VQDOTSU_VX, MASK_VQDOTSU_VX) +DECLARE_INSN(vqdotu_vv, MATCH_VQDOTU_VV, MASK_VQDOTU_VV) +DECLARE_INSN(vqdotu_vx, MATCH_VQDOTU_VX, MASK_VQDOTU_VX) +DECLARE_INSN(vqdotus_vx, MATCH_VQDOTUS_VX, MASK_VQDOTUS_VX) DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) @@ -4071,6 +4068,8 @@ DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) DECLARE_CSR(stimecmp, CSR_STIMECMP) +DECLARE_CSR(sctrctl, CSR_SCTRCTL) +DECLARE_CSR(sctrstatus, CSR_SCTRSTATUS) DECLARE_CSR(siselect, CSR_SISELECT) DECLARE_CSR(sireg, CSR_SIREG) DECLARE_CSR(sireg2, CSR_SIREG2) @@ -4079,6 +4078,7 @@ DECLARE_CSR(sireg4, CSR_SIREG4) DECLARE_CSR(sireg5, CSR_SIREG5) DECLARE_CSR(sireg6, CSR_SIREG6) DECLARE_CSR(stopei, CSR_STOPEI) +DECLARE_CSR(sctrdepth, CSR_SCTRDEPTH) DECLARE_CSR(satp, CSR_SATP) DECLARE_CSR(srmcfg, CSR_SRMCFG) DECLARE_CSR(scontext, CSR_SCONTEXT) @@ -4091,6 +4091,7 @@ DECLARE_CSR(vscause, CSR_VSCAUSE) DECLARE_CSR(vstval, CSR_VSTVAL) DECLARE_CSR(vsip, CSR_VSIP) DECLARE_CSR(vstimecmp, CSR_VSTIMECMP) +DECLARE_CSR(vsctrctl, CSR_VSCTRCTL) DECLARE_CSR(vsiselect, CSR_VSISELECT) DECLARE_CSR(vsireg, CSR_VSIREG) DECLARE_CSR(vsireg2, CSR_VSIREG2) @@ -4163,6 +4164,7 @@ DECLARE_CSR(mtval, CSR_MTVAL) DECLARE_CSR(mip, CSR_MIP) DECLARE_CSR(mtinst, CSR_MTINST) DECLARE_CSR(mtval2, CSR_MTVAL2) +DECLARE_CSR(mctrctl, CSR_MCTRCTL) DECLARE_CSR(miselect, CSR_MISELECT) DECLARE_CSR(mireg, CSR_MIREG) DECLARE_CSR(mireg2, CSR_MIREG2) @@ -4338,6 +4340,7 @@ DECLARE_CSR(stimecmph, CSR_STIMECMPH) DECLARE_CSR(vsieh, CSR_VSIEH) DECLARE_CSR(vsiph, CSR_VSIPH) DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) +DECLARE_CSR(hedelegh, CSR_HEDELEGH) DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) DECLARE_CSR(hidelegh, CSR_HIDELEGH) DECLARE_CSR(hvienh, CSR_HVIENH) @@ -4469,13 +4472,14 @@ DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) -DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) -DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) -DECLARE_CAUSE("virtual_supervisor_ecall", CAUSE_VIRTUAL_SUPERVISOR_ECALL) -DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("user ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("virtual supervisor ecall", CAUSE_VIRTUAL_SUPERVISOR_ECALL) +DECLARE_CAUSE("machine ecall", CAUSE_MACHINE_ECALL) DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +DECLARE_CAUSE("double trap", CAUSE_DOUBLE_TRAP) DECLARE_CAUSE("software check fault", CAUSE_SOFTWARE_CHECK_FAULT) DECLARE_CAUSE("hardware error fault", CAUSE_HARDWARE_ERROR_FAULT) DECLARE_CAUSE("fetch guest page fault", CAUSE_FETCH_GUEST_PAGE_FAULT) diff --git a/riscv/entropy_source.h b/riscv/entropy_source.h index 148e6b0..64e12a1 100644 --- a/riscv/entropy_source.h +++ b/riscv/entropy_source.h @@ -1,3 +1,7 @@ +// See LICENSE for license details. + +#ifndef _RISCV_ENTROPY_SOURCE_H +#define _RISCV_ENTROPY_SOURCE_H #include <fstream> #include <iostream> @@ -116,3 +120,4 @@ public: }; +#endif diff --git a/riscv/execute.cc b/riscv/execute.cc index f263dce..1b572a7 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -40,13 +40,12 @@ static void commit_log_print_value(FILE *log_file, int width, const void *data) fprintf(log_file, "0x%016" PRIx64, *(const uint64_t *)data); break; default: - // max lengh of vector - if (((width - 1) & width) == 0) { - const uint64_t *arr = (const uint64_t *)data; + if (width % 8 == 0) { + const uint8_t *arr = (const uint8_t *)data; fprintf(log_file, "0x"); - for (int idx = width / 64 - 1; idx >= 0; --idx) { - fprintf(log_file, "%016" PRIx64, arr[idx]); + for (int idx = width / 8 - 1; idx >= 0; --idx) { + fprintf(log_file, "%02" PRIx8, arr[idx]); } } else { abort(); @@ -202,7 +201,7 @@ static inline reg_t execute_insn_logged(processor_t* p, reg_t pc, insn_fetch_t f return npc; } -bool processor_t::slow_path() +bool processor_t::slow_path() const { return debug || state.single_step != state.STEP_NONE || state.debug_mode || log_commits_enabled || histogram_enabled || in_wfi || check_triggers_icount; @@ -211,21 +210,31 @@ bool processor_t::slow_path() // fetch/decode/execute loop void processor_t::step(size_t n) { + mmu_t* _mmu = mmu; + if (!state.debug_mode) { if (halt_request == HR_REGULAR) { - enter_debug_mode(DCSR_CAUSE_DEBUGINT); + enter_debug_mode(DCSR_CAUSE_DEBUGINT, 0); } else if (halt_request == HR_GROUP) { - enter_debug_mode(DCSR_CAUSE_GROUP); - } // !!!The halt bit in DCSR is deprecated. - else if (state.dcsr->halt) { - enter_debug_mode(DCSR_CAUSE_HALT); + enter_debug_mode(DCSR_CAUSE_GROUP, 0); + } else if (halt_on_reset) { + halt_on_reset = false; + enter_debug_mode(DCSR_CAUSE_HALT, 0); + } + } + + if (extension_enabled(EXT_ZICCID)) { + // Ziccid requires stores eventually become visible to instruction fetch, + // so periodically flush the I$ + if (ziccid_flush_count-- == 0) { + ziccid_flush_count += ZICCID_FLUSH_PERIOD; + _mmu->flush_icache(); } } while (n > 0) { size_t instret = 0; reg_t pc = state.pc; - mmu_t* _mmu = mmu; state.prv_changed = false; state.v_changed = false; @@ -257,7 +266,7 @@ void processor_t::step(size_t n) if (unlikely(!state.serialized && state.single_step == state.STEP_STEPPED)) { state.single_step = state.STEP_NONE; if (!state.debug_mode) { - enter_debug_mode(DCSR_CAUSE_STEP); + enter_debug_mode(DCSR_CAUSE_STEP, 0); // enter_debug_mode changed state.pc, so we can't just continue. break; } @@ -286,6 +295,17 @@ void processor_t::step(size_t n) disasm(fetch.insn); pc = execute_insn_logged(this, pc, fetch); advance_pc(); + + // Resume from debug mode in critical error + if (state.critical_error && !state.debug_mode) { + if (state.dcsr->read() & DCSR_CETRIG) { + enter_debug_mode(DCSR_CAUSE_EXTCAUSE, DCSR_EXTCAUSE_CRITERR); + } else { + // Handling of critical error is implementation defined + // For now just enter debug mode + enter_debug_mode(DCSR_CAUSE_HALT, 0); + } + } } } else while (instret < n) @@ -311,26 +331,32 @@ void processor_t::step(size_t n) take_trap(t, pc); n = instret; + // If critical error then enter debug mode critical error trigger enabled + if (state.critical_error) { + if (state.dcsr->read() & DCSR_CETRIG) { + enter_debug_mode(DCSR_CAUSE_EXTCAUSE, DCSR_EXTCAUSE_CRITERR); + } else { + // Handling of critical error is implementation defined + // For now just enter debug mode + enter_debug_mode(DCSR_CAUSE_HALT, 0); + } + } // Trigger action takes priority over single step auto match = TM.detect_trap_match(t); if (match.has_value()) take_trigger_action(match->action, 0, state.pc, 0); else if (unlikely(state.single_step == state.STEP_STEPPED)) { state.single_step = state.STEP_NONE; - enter_debug_mode(DCSR_CAUSE_STEP); + enter_debug_mode(DCSR_CAUSE_STEP, 0); } } catch (triggers::matched_t& t) { - if (mmu->matched_trigger) { - delete mmu->matched_trigger; - mmu->matched_trigger = NULL; - } take_trigger_action(t.action, t.address, pc, t.gva); } catch(trap_debug_mode&) { - enter_debug_mode(DCSR_CAUSE_SWBP); + enter_debug_mode(DCSR_CAUSE_SWBP, 0); } catch (wait_for_interrupt_t &t) { @@ -344,10 +370,10 @@ void processor_t::step(size_t n) in_wfi = true; } - state.minstret->bump(instret); + state.minstret->bump((state.mcountinhibit->read() & MCOUNTINHIBIT_IR) ? 0 : instret); // Model a hart whose CPI is 1. - state.mcycle->bump(instret); + state.mcycle->bump((state.mcountinhibit->read() & MCOUNTINHIBIT_CY) ? 0 : instret); n -= instret; } diff --git a/riscv/extension.cc b/riscv/extension.cc index 520c2ed..195eea1 100644 --- a/riscv/extension.cc +++ b/riscv/extension.cc @@ -3,21 +3,15 @@ #include "extension.h" #include "trap.h" -extension_t::~extension_t() -{ -} - -void extension_t::illegal_instruction() +void extension_t::illegal_instruction([[maybe_unused]] processor_t &proc) { throw trap_illegal_instruction(0); } -void extension_t::raise_interrupt() +void extension_t::raise_interrupt([[maybe_unused]] processor_t &proc) { - p->take_interrupt((reg_t)1 << IRQ_COP); // must not return + proc.take_interrupt((reg_t)1 << IRQ_COP); // must not return throw std::logic_error("a COP exception was posted, but interrupts are disabled!"); } -void extension_t::clear_interrupt() -{ -} +void extension_t::clear_interrupt([[maybe_unused]] processor_t &proc) {} diff --git a/riscv/extension.h b/riscv/extension.h index de6ece3..411e65b 100644 --- a/riscv/extension.h +++ b/riscv/extension.h @@ -11,20 +11,18 @@ class extension_t { public: - virtual std::vector<insn_desc_t> get_instructions() = 0; - virtual std::vector<disasm_insn_t*> get_disasms() = 0; - virtual const char* name() = 0; - virtual void reset() {}; - virtual void set_debug(bool UNUSED value) {} - virtual ~extension_t(); + virtual std::vector<insn_desc_t> get_instructions(const processor_t &proc) = 0; + virtual std::vector<disasm_insn_t*> get_disasms(const processor_t *proc = nullptr) = 0; + virtual std::vector<csr_t_p> get_csrs(processor_t &) const { return {}; }; + virtual const char* name() const = 0; + virtual void reset(processor_t &) {}; + virtual void set_debug(bool UNUSED value, const processor_t &) {} + virtual ~extension_t() = default; - void set_processor(processor_t* _p) { p = _p; } protected: - processor_t* p; - - void illegal_instruction(); - void raise_interrupt(); - void clear_interrupt(); + void illegal_instruction(processor_t &proc); + void raise_interrupt(processor_t &proc); + void clear_interrupt(processor_t &proc); }; std::function<extension_t*()> find_extension(const char* name); diff --git a/riscv/insn_template.cc b/riscv/insn_template.cc index 9194d19..168e2dc 100644 --- a/riscv/insn_template.cc +++ b/riscv/insn_template.cc @@ -5,24 +5,29 @@ #define DECODE_MACRO_USAGE_LOGGED 0 +#define PROLOGUE \ + reg_t npc = sext_xlen(pc + insn_length(OPCODE)) + +#define EPILOGUE \ + trace_opcode(p, OPCODE, insn); \ + return npc + reg_t fast_rv32i_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 32 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } reg_t fast_rv64i_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 64 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } #undef DECODE_MACRO_USAGE_LOGGED @@ -31,21 +36,19 @@ reg_t fast_rv64i_NAME(processor_t* p, insn_t insn, reg_t pc) reg_t logged_rv32i_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 32 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } reg_t logged_rv64i_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 64 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } #undef CHECK_REG @@ -57,21 +60,19 @@ reg_t logged_rv64i_NAME(processor_t* p, insn_t insn, reg_t pc) reg_t fast_rv32e_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 32 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } reg_t fast_rv64e_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 64 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } #undef DECODE_MACRO_USAGE_LOGGED @@ -80,19 +81,17 @@ reg_t fast_rv64e_NAME(processor_t* p, insn_t insn, reg_t pc) reg_t logged_rv32e_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 32 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } reg_t logged_rv64e_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 64 - reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + PROLOGUE; #include "insns/NAME.h" - trace_opcode(p, OPCODE, insn); + EPILOGUE; #undef xlen - return npc; } diff --git a/riscv/insns/bclri.h b/riscv/insns/bclri.h index 8df6a5f..7ab4250 100644 --- a/riscv/insns/bclri.h +++ b/riscv/insns/bclri.h @@ -1,3 +1,4 @@ require_extension(EXT_ZBS); +require(SHAMT < xlen); int shamt = SHAMT & (xlen-1); WRITE_RD(sext_xlen(RS1 & ~(1LL << shamt))); diff --git a/riscv/insns/bexti.h b/riscv/insns/bexti.h index 31d2316..bf86ab4 100644 --- a/riscv/insns/bexti.h +++ b/riscv/insns/bexti.h @@ -1,3 +1,4 @@ require_extension(EXT_ZBS); +require(SHAMT < xlen); int shamt = SHAMT & (xlen-1); WRITE_RD(sext_xlen(1 & (RS1 >> shamt))); diff --git a/riscv/insns/binvi.h b/riscv/insns/binvi.h index 3272d39..7f6723c 100644 --- a/riscv/insns/binvi.h +++ b/riscv/insns/binvi.h @@ -1,3 +1,4 @@ require_extension(EXT_ZBS); +require(SHAMT < xlen); int shamt = SHAMT & (xlen-1); WRITE_RD(sext_xlen(RS1 ^ (1LL << shamt))); diff --git a/riscv/insns/bseti.h b/riscv/insns/bseti.h index 4952378..8ef4b37 100644 --- a/riscv/insns/bseti.h +++ b/riscv/insns/bseti.h @@ -1,3 +1,4 @@ require_extension(EXT_ZBS); +require(SHAMT < xlen); int shamt = SHAMT & (xlen-1); WRITE_RD(sext_xlen(RS1 | (1LL << shamt))); diff --git a/riscv/insns/c_ld.h b/riscv/insns/c_ld.h index 18e0d5e..951243c 100644 --- a/riscv/insns/c_ld.h +++ b/riscv/insns/c_ld.h @@ -1,5 +1,5 @@ require_extension(EXT_ZCA); -require((xlen == 64) || p->extension_enabled(EXT_ZCMLSD)); +require((xlen == 64) || p->extension_enabled(EXT_ZCLSD)); if (xlen == 32) { WRITE_RVC_RS2S_PAIR(MMU.load<int64_t>(RVC_RS1S + insn.rvc_ld_imm())); diff --git a/riscv/insns/c_ldsp.h b/riscv/insns/c_ldsp.h index d8c8ec8..9f44fec 100644 --- a/riscv/insns/c_ldsp.h +++ b/riscv/insns/c_ldsp.h @@ -1,5 +1,5 @@ require_extension(EXT_ZCA); -require((xlen == 64) || p->extension_enabled(EXT_ZCMLSD)); +require((xlen == 64) || p->extension_enabled(EXT_ZCLSD)); require(insn.rvc_rd() != 0); if (xlen == 32) { diff --git a/riscv/insns/c_sd.h b/riscv/insns/c_sd.h index dba9b07..860e2de 100644 --- a/riscv/insns/c_sd.h +++ b/riscv/insns/c_sd.h @@ -1,5 +1,5 @@ require_extension(EXT_ZCA); -require((xlen == 64) || p->extension_enabled(EXT_ZCMLSD)); +require((xlen == 64) || p->extension_enabled(EXT_ZCLSD)); if (xlen == 32) { MMU.store<uint64_t>(RVC_RS1S + insn.rvc_ld_imm(), RVC_RS2S_PAIR); diff --git a/riscv/insns/c_sdsp.h b/riscv/insns/c_sdsp.h index e95aefa..e6b1f62 100644 --- a/riscv/insns/c_sdsp.h +++ b/riscv/insns/c_sdsp.h @@ -1,5 +1,5 @@ require_extension(EXT_ZCA); -require((xlen == 64) || p->extension_enabled(EXT_ZCMLSD)); +require((xlen == 64) || p->extension_enabled(EXT_ZCLSD)); if (xlen == 32) { MMU.store<uint64_t>(RVC_SP + insn.rvc_sdsp_imm(), RVC_RS2_PAIR); diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h index bdcf3db..0f94f88 100644 --- a/riscv/insns/dret.h +++ b/riscv/insns/dret.h @@ -4,8 +4,22 @@ if (ZICFILP_xLPE(STATE.dcsr->v, STATE.dcsr->prv)) { STATE.elp = STATE.dcsr->pelp; } p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v); -if (STATE.prv < PRV_M) +if (STATE.prv < PRV_M) { STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV); + STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MDT); +} + +if (STATE.dcsr->prv == PRV_U || STATE.dcsr->v) + STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT); + +if (STATE.dcsr->v && STATE.dcsr->prv == PRV_U) + STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT); + +if (STATE.dcsr->prv == PRV_U || STATE.dcsr->v) + STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT); + +if (STATE.dcsr->v && STATE.dcsr->prv == PRV_U) + STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT); /* We're not in Debug Mode anymore. */ STATE.debug_mode = false; diff --git a/riscv/insns/fcvtmod_w_d.h b/riscv/insns/fcvtmod_w_d.h index e39400d..231f605 100644 --- a/riscv/insns/fcvtmod_w_d.h +++ b/riscv/insns/fcvtmod_w_d.h @@ -55,6 +55,5 @@ if (exp == 0) { } WRITE_RD(sext32(frac)); -STATE.fflags->write(STATE.fflags->read() | - (inexact ? softfloat_flag_inexact : 0) | +raise_fp_exceptions((inexact ? softfloat_flag_inexact : 0) | (invalid ? softfloat_flag_invalid : 0)); diff --git a/riscv/insns/jal.h b/riscv/insns/jal.h index cd59964..e7a75c7 100644 --- a/riscv/insns/jal.h +++ b/riscv/insns/jal.h @@ -1,3 +1,4 @@ +CHECK_RD(); reg_t tmp = npc; set_pc(JUMP_TARGET); WRITE_RD(tmp); diff --git a/riscv/insns/jalr.h b/riscv/insns/jalr.h index 0606f67..de84e89 100644 --- a/riscv/insns/jalr.h +++ b/riscv/insns/jalr.h @@ -1,3 +1,4 @@ +CHECK_RD(); reg_t tmp = npc; set_pc((RS1 + insn.i_imm()) & ~reg_t(1)); WRITE_RD(tmp); diff --git a/riscv/insns/mnret.h b/riscv/insns/mnret.h index 30f1081..2003cbe 100644 --- a/riscv/insns/mnret.h +++ b/riscv/insns/mnret.h @@ -10,5 +10,11 @@ if (prev_prv != PRV_M) { STATE.mstatus->write(mstatus); } s = set_field(s, MNSTATUS_NMIE, 1); +if (ZICFILP_xLPE(prev_virt, prev_prv)) { + STATE.elp = static_cast<elp_t>(get_field(s, MNSTATUS_MNPELP)); +} +if (p->extension_enabled(EXT_ZICFILP)) { + s = set_field(s, MNSTATUS_MNPELP, elp_t::NO_LP_EXPECTED); +} STATE.mnstatus->write(s); p->set_privilege(prev_prv, prev_virt); diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h index 3fe920c..479bfca 100644 --- a/riscv/insns/mret.h +++ b/riscv/insns/mret.h @@ -13,7 +13,12 @@ if (ZICFILP_xLPE(prev_virt, prev_prv)) { STATE.elp = static_cast<elp_t>(get_field(s, MSTATUS_MPELP)); } s = set_field(s, MSTATUS_MPELP, elp_t::NO_LP_EXPECTED); +s = set_field(s, MSTATUS_MDT, 0); +if (prev_prv == PRV_U || (prev_virt && prev_prv != PRV_M)) + s = set_field(s, MSTATUS_SDT, 0); +if (prev_virt && prev_prv == PRV_U) + STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT); STATE.mstatus->write(s); if (STATE.mstatush) STATE.mstatush->write(s >> 32); // log mstatush change -STATE.tcontrol->write((STATE.tcontrol->read() & CSR_TCONTROL_MPTE) ? (CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE) : 0); +if (STATE.tcontrol) STATE.tcontrol->write((STATE.tcontrol->read() & CSR_TCONTROL_MPTE) ? (CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE) : 0); p->set_privilege(prev_prv, prev_virt); diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h index 23a13b5..efb4fa6 100644 --- a/riscv/insns/sret.h +++ b/riscv/insns/sret.h @@ -26,6 +26,22 @@ if (!STATE.v) { if (ZICFILP_xLPE(prev_virt, prev_prv)) { STATE.elp = static_cast<elp_t>(get_field(s, SSTATUS_SPELP)); } + +if (STATE.prv == PRV_M) { + STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MDT); + if (prev_prv == PRV_U || prev_virt) + STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT); + if (prev_virt && prev_prv == PRV_U) + STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT); +} + s = set_field(s, SSTATUS_SPELP, elp_t::NO_LP_EXPECTED); + +if (STATE.prv == PRV_S) { + s = set_field(s, SSTATUS_SDT, 0); + if (!STATE.v && prev_virt && prev_prv == PRV_U) + STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT); +} + STATE.sstatus->write(s); p->set_privilege(prev_prv, prev_virt); diff --git a/riscv/insns/ssrdp.h b/riscv/insns/ssrdp.h index 20b0856..bf20504 100644 --- a/riscv/insns/ssrdp.h +++ b/riscv/insns/ssrdp.h @@ -1,7 +1,7 @@ #include "zicfiss.h" if (xSSE()) { - WRITE_RD(STATE.ssp->read()); + WRITE_RD(sext_xlen(STATE.ssp->read())); } else { #include "mop_r_N.h" } diff --git a/riscv/insns/vcompress_vm.h b/riscv/insns/vcompress_vm.h index d35b8ba..6624d8b 100644 --- a/riscv/insns/vcompress_vm.h +++ b/riscv/insns/vcompress_vm.h @@ -1,4 +1,5 @@ // vcompress vd, vs2, vs1 +require(P.any_vector_extensions()); require(P.VU.vstart->read() == 0); require_align(insn.rd(), P.VU.vflmul); require_align(insn.rs2(), P.VU.vflmul); @@ -8,11 +9,7 @@ require_noover(insn.rd(), P.VU.vflmul, insn.rs1(), 1); reg_t pos = 0; VI_GENERAL_LOOP_BASE - const int midx = i / 64; - const int mpos = i % 64; - - bool do_mask = (P.VU.elt<uint64_t>(rs1_num, midx) >> mpos) & 0x1; - if (do_mask) { + if (P.VU.mask_elt(rs1_num, i)) { switch (sew) { case e8: P.VU.elt<uint8_t>(rd_num, pos, true) = P.VU.elt<uint8_t>(rs2_num, i); diff --git a/riscv/insns/vcpop_m.h b/riscv/insns/vcpop_m.h index f909311..26a1276 100644 --- a/riscv/insns/vcpop_m.h +++ b/riscv/insns/vcpop_m.h @@ -6,15 +6,7 @@ reg_t rs2_num = insn.rs2(); require(P.VU.vstart->read() == 0); reg_t popcount = 0; for (reg_t i=P.VU.vstart->read(); i<vl; ++i) { - const int midx = i / 32; - const int mpos = i % 32; - - bool vs2_lsb = ((P.VU.elt<uint32_t>(rs2_num, midx ) >> mpos) & 0x1) == 1; - if (insn.v_vm() == 1) { - popcount += vs2_lsb; - } else { - bool do_mask = (P.VU.elt<uint32_t>(0, midx) >> mpos) & 0x1; - popcount += (vs2_lsb && do_mask); - } + bool vs2_bit = P.VU.mask_elt(rs2_num, i); + popcount += vs2_bit && (insn.v_vm() || P.VU.mask_elt(0, i)); } WRITE_RD(popcount); diff --git a/riscv/insns/vfirst_m.h b/riscv/insns/vfirst_m.h index a130e5d..e3f5263 100644 --- a/riscv/insns/vfirst_m.h +++ b/riscv/insns/vfirst_m.h @@ -8,8 +8,7 @@ reg_t pos = -1; for (reg_t i=P.VU.vstart->read(); i < vl; ++i) { VI_LOOP_ELEMENT_SKIP() - bool vs2_lsb = ((P.VU.elt<uint64_t>(rs2_num, midx ) >> mpos) & 0x1) == 1; - if (vs2_lsb) { + if (P.VU.mask_elt(rs2_num, i)) { pos = i; break; } diff --git a/riscv/insns/vfrsqrt7_v.h b/riscv/insns/vfrsqrt7_v.h index a073764..2505639 100644 --- a/riscv/insns/vfrsqrt7_v.h +++ b/riscv/insns/vfrsqrt7_v.h @@ -1,4 +1,4 @@ -// vfclass.v vd, vs2, vm +// vfrsqrt7.v vd, vs2, vm VI_VFP_V_LOOP ({ vd = f16_rsqrte7(vs2); diff --git a/riscv/insns/vghsh_vv.h b/riscv/insns/vghsh_vv.h index bcbfe74..728678c 100644 --- a/riscv/insns/vghsh_vv.h +++ b/riscv/insns/vghsh_vv.h @@ -2,9 +2,13 @@ #include "zvk_ext_macros.h" +const uint32_t EGS = 4; + require_zvkg; require(P.VU.vsew == 32); require_egw_fits(128); +require(P.VU.vl->read() % EGS == 0); +VI_CHECK_SSS(true) VI_ZVK_VD_VS1_VS2_EGU32x4_NOVM_LOOP( {}, diff --git a/riscv/insns/vgmul_vv.h b/riscv/insns/vgmul_vv.h index 820b396..0d223e8 100644 --- a/riscv/insns/vgmul_vv.h +++ b/riscv/insns/vgmul_vv.h @@ -2,9 +2,13 @@ #include "zvk_ext_macros.h" +const uint32_t EGS = 4; + require_zvkg; require(P.VU.vsew == 32); require_egw_fits(128); +require(P.VU.vl->read() % EGS == 0); +VI_CHECK_SSS(false) VI_ZVK_VD_VS2_EGU32x4_NOVM_LOOP( {}, diff --git a/riscv/insns/viota_m.h b/riscv/insns/viota_m.h index 1ee9229..00155db 100644 --- a/riscv/insns/viota_m.h +++ b/riscv/insns/viota_m.h @@ -12,36 +12,31 @@ require_noover(rd_num, P.VU.vflmul, rs2_num, 1); int cnt = 0; for (reg_t i = 0; i < vl; ++i) { - const int midx = i / 64; - const int mpos = i % 64; - - bool vs2_lsb = ((P.VU.elt<uint64_t>(rs2_num, midx) >> mpos) & 0x1) == 1; - bool do_mask = (P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1; + bool do_mask = P.VU.mask_elt(0, i); bool has_one = false; if (insn.v_vm() == 1 || (insn.v_vm() == 0 && do_mask)) { - if (vs2_lsb) { + if (P.VU.mask_elt(rs2_num, i)) { has_one = true; } } - bool use_ori = (insn.v_vm() == 0) && !do_mask; + // Bypass masked-off elements + if ((insn.v_vm() == 0) && !do_mask) + continue; + switch (sew) { case e8: - P.VU.elt<uint8_t>(rd_num, i, true) = use_ori ? - P.VU.elt<uint8_t>(rd_num, i) : cnt; + P.VU.elt<uint8_t>(rd_num, i, true) = cnt; break; case e16: - P.VU.elt<uint16_t>(rd_num, i, true) = use_ori ? - P.VU.elt<uint16_t>(rd_num, i) : cnt; + P.VU.elt<uint16_t>(rd_num, i, true) = cnt; break; case e32: - P.VU.elt<uint32_t>(rd_num, i, true) = use_ori ? - P.VU.elt<uint32_t>(rd_num, i) : cnt; + P.VU.elt<uint32_t>(rd_num, i, true) = cnt; break; default: - P.VU.elt<uint64_t>(rd_num, i, true) = use_ori ? - P.VU.elt<uint64_t>(rd_num, i) : cnt; + P.VU.elt<uint64_t>(rd_num, i, true) = cnt; break; } diff --git a/riscv/insns/vmandn_mm.h b/riscv/insns/vmandn_mm.h index e9a87cf..49129f7 100644 --- a/riscv/insns/vmandn_mm.h +++ b/riscv/insns/vmandn_mm.h @@ -1,2 +1,2 @@ // vmandn.mm vd, vs2, vs1 -VI_LOOP_MASK(vs2 & ~vs1); +VI_LOOP_MASK(vs2 & !vs1); diff --git a/riscv/insns/vmnand_mm.h b/riscv/insns/vmnand_mm.h index 5a3ab09..4659e2f 100644 --- a/riscv/insns/vmnand_mm.h +++ b/riscv/insns/vmnand_mm.h @@ -1,2 +1,2 @@ // vmnand.mm vd, vs2, vs1 -VI_LOOP_MASK(~(vs2 & vs1)); +VI_LOOP_MASK(!(vs2 & vs1)); diff --git a/riscv/insns/vmnor_mm.h b/riscv/insns/vmnor_mm.h index ab93378..37327c0 100644 --- a/riscv/insns/vmnor_mm.h +++ b/riscv/insns/vmnor_mm.h @@ -1,2 +1,2 @@ // vmnor.mm vd, vs2, vs1 -VI_LOOP_MASK(~(vs2 | vs1)); +VI_LOOP_MASK(!(vs2 | vs1)); diff --git a/riscv/insns/vmorn_mm.h b/riscv/insns/vmorn_mm.h index 23026f5..71acc05 100644 --- a/riscv/insns/vmorn_mm.h +++ b/riscv/insns/vmorn_mm.h @@ -1,2 +1,2 @@ // vmorn.mm vd, vs2, vs1 -VI_LOOP_MASK(vs2 | ~vs1); +VI_LOOP_MASK(vs2 | !vs1); diff --git a/riscv/insns/vmsbf_m.h b/riscv/insns/vmsbf_m.h index 1275872..3f736e0 100644 --- a/riscv/insns/vmsbf_m.h +++ b/riscv/insns/vmsbf_m.h @@ -11,22 +11,17 @@ reg_t rs2_num = insn.rs2(); bool has_one = false; for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { - const int midx = i / 64; - const int mpos = i % 64; - const uint64_t mmask = UINT64_C(1) << mpos; \ - - bool vs2_lsb = ((P.VU.elt<uint64_t>(rs2_num, midx) >> mpos) & 0x1) == 1; - bool do_mask = (P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1; - + bool vs2_lsb = P.VU.mask_elt(rs2_num, i); + bool do_mask = P.VU.mask_elt(0, i); if (insn.v_vm() == 1 || (insn.v_vm() == 0 && do_mask)) { - auto &vd = P.VU.elt<uint64_t>(rd_num, midx, true); - uint64_t res = 0; + bool res = false; if (!has_one && !vs2_lsb) { - res = 1; + res = true; } else if (!has_one && vs2_lsb) { has_one = true; } - vd = (vd & ~mmask) | ((res << mpos) & mmask); + + P.VU.set_mask_elt(rd_num, i, res); } } diff --git a/riscv/insns/vmsif_m.h b/riscv/insns/vmsif_m.h index cbcbc2a..b029327 100644 --- a/riscv/insns/vmsif_m.h +++ b/riscv/insns/vmsif_m.h @@ -11,22 +11,18 @@ reg_t rs2_num = insn.rs2(); bool has_one = false; for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { - const int midx = i / 64; - const int mpos = i % 64; - const uint64_t mmask = UINT64_C(1) << mpos; \ - - bool vs2_lsb = ((P.VU.elt<uint64_t>(rs2_num, midx ) >> mpos) & 0x1) == 1; - bool do_mask = (P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1; + bool vs2_lsb = P.VU.mask_elt(rs2_num, i); + bool do_mask = P.VU.mask_elt(0, i); if (insn.v_vm() == 1 || (insn.v_vm() == 0 && do_mask)) { - auto &vd = P.VU.elt<uint64_t>(rd_num, midx, true); - uint64_t res = 0; + bool res = false; if (!has_one && !vs2_lsb) { - res = 1; + res = true; } else if (!has_one && vs2_lsb) { has_one = true; - res = 1; + res = true; } - vd = (vd & ~mmask) | ((res << mpos) & mmask); + + P.VU.set_mask_elt(rd_num, i, res); } } diff --git a/riscv/insns/vmsof_m.h b/riscv/insns/vmsof_m.h index 9bd4f0c..5753dbf 100644 --- a/riscv/insns/vmsof_m.h +++ b/riscv/insns/vmsof_m.h @@ -11,20 +11,16 @@ reg_t rs2_num = insn.rs2(); bool has_one = false; for (reg_t i = P.VU.vstart->read() ; i < vl; ++i) { - const int midx = i / 64; - const int mpos = i % 64; - const uint64_t mmask = UINT64_C(1) << mpos; \ - - bool vs2_lsb = ((P.VU.elt<uint64_t>(rs2_num, midx ) >> mpos) & 0x1) == 1; - bool do_mask = (P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1; + bool vs2_lsb = P.VU.mask_elt(rs2_num, i); + bool do_mask = P.VU.mask_elt(0, i); if (insn.v_vm() == 1 || (insn.v_vm() == 0 && do_mask)) { - uint64_t &vd = P.VU.elt<uint64_t>(rd_num, midx, true); - uint64_t res = 0; + bool res = false; if (!has_one && vs2_lsb) { has_one = true; - res = 1; + res = true; } - vd = (vd & ~mmask) | ((res << mpos) & mmask); + + P.VU.set_mask_elt(rd_num, i, res); } } diff --git a/riscv/insns/vmulhu_vv.h b/riscv/insns/vmulhu_vv.h index 8e318ed..0ff488c 100644 --- a/riscv/insns/vmulhu_vv.h +++ b/riscv/insns/vmulhu_vv.h @@ -1,4 +1,4 @@ -// vmulhu vd ,vs2, vs1 +// vmulhu vd, vs2, vs1 VI_VV_ULOOP ({ vd = ((uint128_t)vs2 * vs1) >> sew; diff --git a/riscv/insns/vmxnor_mm.h b/riscv/insns/vmxnor_mm.h index 0736d5b..8db61c2 100644 --- a/riscv/insns/vmxnor_mm.h +++ b/riscv/insns/vmxnor_mm.h @@ -1,2 +1,2 @@ // vmnxor.mm vd, vs2, vs1 -VI_LOOP_MASK(~(vs2 ^ vs1)); +VI_LOOP_MASK(!(vs2 ^ vs1)); diff --git a/riscv/insns/vnclip_wi.h b/riscv/insns/vnclip_wi.h index ea6898c..4805173 100644 --- a/riscv/insns/vnclip_wi.h +++ b/riscv/insns/vnclip_wi.h @@ -1,9 +1,9 @@ // vnclip: vd[i] = clip(round(vs2[i] + rnd) >> simm) -VRM xrm = P.VU.get_vround_mode(); -int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); -int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); VI_VI_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); + int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); int128_t result = vs2; unsigned shift = zimm5 & ((sew * 2) - 1); diff --git a/riscv/insns/vnclip_wv.h b/riscv/insns/vnclip_wv.h index 63b84c6..1f7558a 100644 --- a/riscv/insns/vnclip_wv.h +++ b/riscv/insns/vnclip_wv.h @@ -1,9 +1,9 @@ // vnclip: vd[i] = clip(round(vs2[i] + rnd) >> vs1[i]) -VRM xrm = P.VU.get_vround_mode(); -int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); -int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); VI_VV_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); + int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); int128_t result = vs2; unsigned shift = vs1 & ((sew * 2) - 1); diff --git a/riscv/insns/vnclip_wx.h b/riscv/insns/vnclip_wx.h index 482eace..fffebaf 100644 --- a/riscv/insns/vnclip_wx.h +++ b/riscv/insns/vnclip_wx.h @@ -1,9 +1,9 @@ // vnclip: vd[i] = clip(round(vs2[i] + rnd) >> rs1[i]) -VRM xrm = P.VU.get_vround_mode(); -int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); -int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); VI_VX_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); + int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); int128_t result = vs2; unsigned shift = rs1 & ((sew * 2) - 1); diff --git a/riscv/insns/vnclipu_wi.h b/riscv/insns/vnclipu_wi.h index 441a3a7..10735ba 100644 --- a/riscv/insns/vnclipu_wi.h +++ b/riscv/insns/vnclipu_wi.h @@ -1,9 +1,9 @@ // vnclipu: vd[i] = clip(round(vs2[i] + rnd) >> simm) -VRM xrm = P.VU.get_vround_mode(); -uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); -uint64_t sign_mask = UINT64_MAX << P.VU.vsew; VI_VI_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); + uint64_t sign_mask = UINT64_MAX << P.VU.vsew; uint128_t result = vs2_u; unsigned shift = zimm5 & ((sew * 2) - 1); diff --git a/riscv/insns/vnclipu_wv.h b/riscv/insns/vnclipu_wv.h index 8072489..0e3e8b0 100644 --- a/riscv/insns/vnclipu_wv.h +++ b/riscv/insns/vnclipu_wv.h @@ -1,9 +1,9 @@ // vnclipu: vd[i] = clip(round(vs2[i] + rnd) >> vs1[i]) -VRM xrm = P.VU.get_vround_mode(); -uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); -uint64_t sign_mask = UINT64_MAX << P.VU.vsew; VI_VV_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); + uint64_t sign_mask = UINT64_MAX << P.VU.vsew; uint128_t result = vs2_u; unsigned shift = vs1 & ((sew * 2) - 1); diff --git a/riscv/insns/vnclipu_wx.h b/riscv/insns/vnclipu_wx.h index b2d91c3..d7c6bea 100644 --- a/riscv/insns/vnclipu_wx.h +++ b/riscv/insns/vnclipu_wx.h @@ -1,9 +1,9 @@ // vnclipu: vd[i] = clip(round(vs2[i] + rnd) >> rs1[i]) -VRM xrm = P.VU.get_vround_mode(); -uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); -uint64_t sign_mask = UINT64_MAX << P.VU.vsew; VI_VX_LOOP_NARROW ({ + VRM xrm = P.VU.get_vround_mode(); + uint64_t uint_max = UINT64_MAX >> (64 - P.VU.vsew); + uint64_t sign_mask = UINT64_MAX << P.VU.vsew; uint128_t result = vs2_u; unsigned shift = rs1 & ((sew * 2) - 1); diff --git a/riscv/insns/vnsra_wi.h b/riscv/insns/vnsra_wi.h index 0502ff1..ec7f637 100644 --- a/riscv/insns/vnsra_wi.h +++ b/riscv/insns/vnsra_wi.h @@ -1,5 +1,5 @@ // vnsra.vi vd, vs2, zimm5 VI_VI_LOOP_NSHIFT ({ - vd = vs2 >> (zimm5 & (sew * 2 - 1) & 0x1f); + vd = vs2 >> (zimm5 & (sew * 2 - 1)); }) diff --git a/riscv/insns/vqdot_common.h b/riscv/insns/vqdot_common.h new file mode 100644 index 0000000..381e1a4 --- /dev/null +++ b/riscv/insns/vqdot_common.h @@ -0,0 +1,15 @@ +#define UNPACK_32_TO_8(IN, TYPE, OUT_ARR) \ + int64_t OUT_ARR[4]; \ + OUT_ARR[0] = (TYPE)((IN) & 0xff); \ + OUT_ARR[1] = (TYPE)((IN >> 8) & 0xff); \ + OUT_ARR[2] = (TYPE)((IN >> 16) & 0xff); \ + OUT_ARR[3] = (TYPE)((IN >> 24) & 0xff); \ + +#define VQDOT(IN1, IN2, TYPE1, TYPE2) \ + UNPACK_32_TO_8(IN1, TYPE1, unpacked_vs1) \ + UNPACK_32_TO_8(IN2, TYPE2, unpacked_vs2) \ + uint64_t result = unpacked_vs1[0]*unpacked_vs2[0] + \ + unpacked_vs1[1]*unpacked_vs2[1] + \ + unpacked_vs1[2]*unpacked_vs2[2] + \ + unpacked_vs1[3]*unpacked_vs2[3] \ + diff --git a/riscv/insns/vqdot_vv.h b/riscv/insns/vqdot_vv.h new file mode 100644 index 0000000..47a95ce --- /dev/null +++ b/riscv/insns/vqdot_vv.h @@ -0,0 +1,11 @@ +// vqdot.vv vd, vs2, vs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VV_LOOP +({ + VQDOT(vs1, vs2, int8_t, int8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdot_vx.h b/riscv/insns/vqdot_vx.h new file mode 100644 index 0000000..6143b90 --- /dev/null +++ b/riscv/insns/vqdot_vx.h @@ -0,0 +1,11 @@ +// vqdot.vx vd, vs2, rs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VX_LOOP +({ + VQDOT(rs1, vs2, int8_t, int8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdotsu_vv.h b/riscv/insns/vqdotsu_vv.h new file mode 100644 index 0000000..e08b536 --- /dev/null +++ b/riscv/insns/vqdotsu_vv.h @@ -0,0 +1,11 @@ +// vqdotsu.vv vd, vs2, vs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VV_LOOP +({ + VQDOT(vs1, vs2, uint8_t, int8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdotsu_vx.h b/riscv/insns/vqdotsu_vx.h new file mode 100644 index 0000000..f3f3b5c --- /dev/null +++ b/riscv/insns/vqdotsu_vx.h @@ -0,0 +1,11 @@ +// vqdotsu.vx vd, vs2, rs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VX_LOOP +({ + VQDOT(rs1, vs2, uint8_t, int8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdotu_vv.h b/riscv/insns/vqdotu_vv.h new file mode 100644 index 0000000..3404156 --- /dev/null +++ b/riscv/insns/vqdotu_vv.h @@ -0,0 +1,11 @@ +// vqdotu.vv vd, vs2, vs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VV_LOOP +({ + VQDOT(vs1, vs2, uint8_t, uint8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdotu_vx.h b/riscv/insns/vqdotu_vx.h new file mode 100644 index 0000000..7ef1048 --- /dev/null +++ b/riscv/insns/vqdotu_vx.h @@ -0,0 +1,11 @@ +// vqdotu.vx vd, vs2, rs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VX_LOOP +({ + VQDOT(rs1, vs2, uint8_t, uint8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vqdotus_vx.h b/riscv/insns/vqdotus_vx.h new file mode 100644 index 0000000..f1676e9 --- /dev/null +++ b/riscv/insns/vqdotus_vx.h @@ -0,0 +1,11 @@ +// vqdotus.vx vd, vs2, rs1, vm +#include "vqdot_common.h" + +require_extension(EXT_ZVQDOTQ); +require(P.VU.vsew == e32); + +VI_VX_LOOP +({ + VQDOT(rs1, vs2, int8_t, uint8_t); + vd = (vd + result) & 0xffffffff; +}) diff --git a/riscv/insns/vredand_vs.h b/riscv/insns/vredand_vs.h index 6c2d908..2e11182 100644 --- a/riscv/insns/vredand_vs.h +++ b/riscv/insns/vredand_vs.h @@ -1,4 +1,4 @@ -// vredand.vs vd, vs2 ,vs1 +// vredand.vs vd, vs2, vs1 VI_VV_LOOP_REDUCTION ({ vd_0_res &= vs2; diff --git a/riscv/insns/vredmaxu_vs.h b/riscv/insns/vredmaxu_vs.h index 960f486..8499258 100644 --- a/riscv/insns/vredmaxu_vs.h +++ b/riscv/insns/vredmaxu_vs.h @@ -1,4 +1,4 @@ -// vredmaxu.vs vd, vs2 ,vs1 +// vredmaxu.vs vd, vs2, vs1 VI_VV_ULOOP_REDUCTION ({ vd_0_res = (vd_0_res >= vs2) ? vd_0_res : vs2; diff --git a/riscv/insns/vredmin_vs.h b/riscv/insns/vredmin_vs.h index 50359b7..9cbfa42 100644 --- a/riscv/insns/vredmin_vs.h +++ b/riscv/insns/vredmin_vs.h @@ -1,4 +1,4 @@ -// vredmin.vs vd, vs2 ,vs1 +// vredmin.vs vd, vs2, vs1 VI_VV_LOOP_REDUCTION ({ vd_0_res = (vd_0_res <= vs2) ? vd_0_res : vs2; diff --git a/riscv/insns/vredminu_vs.h b/riscv/insns/vredminu_vs.h index 7082475..ac3c080 100644 --- a/riscv/insns/vredminu_vs.h +++ b/riscv/insns/vredminu_vs.h @@ -1,4 +1,4 @@ -// vredminu.vs vd, vs2 ,vs1 +// vredminu.vs vd, vs2, vs1 VI_VV_ULOOP_REDUCTION ({ vd_0_res = (vd_0_res <= vs2) ? vd_0_res : vs2; diff --git a/riscv/insns/vredor_vs.h b/riscv/insns/vredor_vs.h index f7acd9a..24e1496 100644 --- a/riscv/insns/vredor_vs.h +++ b/riscv/insns/vredor_vs.h @@ -1,4 +1,4 @@ -// vredor.vs vd, vs2 ,vs1 +// vredor.vs vd, vs2, vs1 VI_VV_LOOP_REDUCTION ({ vd_0_res |= vs2; diff --git a/riscv/insns/vredsum_vs.h b/riscv/insns/vredsum_vs.h index c4fefe5..d470ec0 100644 --- a/riscv/insns/vredsum_vs.h +++ b/riscv/insns/vredsum_vs.h @@ -1,4 +1,4 @@ -// vredsum.vs vd, vs2 ,vs1 +// vredsum.vs vd, vs2, vs1 VI_VV_LOOP_REDUCTION ({ vd_0_res += vs2; diff --git a/riscv/insns/vredxor_vs.h b/riscv/insns/vredxor_vs.h index bb81ad9..3b3709a 100644 --- a/riscv/insns/vredxor_vs.h +++ b/riscv/insns/vredxor_vs.h @@ -1,4 +1,4 @@ -// vredxor.vs vd, vs2 ,vs1 +// vredxor.vs vd, vs2, vs1 VI_VV_LOOP_REDUCTION ({ vd_0_res ^= vs2; diff --git a/riscv/insns/vsll_vi.h b/riscv/insns/vsll_vi.h index be46506..d9ef5db 100644 --- a/riscv/insns/vsll_vi.h +++ b/riscv/insns/vsll_vi.h @@ -1,5 +1,5 @@ // vsll.vi vd, vs2, zimm5 -VI_VI_LOOP +VI_VI_ULOOP ({ - vd = vs2 << (simm5 & (sew - 1) & 0x1f); + vd = vs2 << (zimm5 & (sew - 1)); }) diff --git a/riscv/insns/vsll_vv.h b/riscv/insns/vsll_vv.h index ce82022..3a3ee18 100644 --- a/riscv/insns/vsll_vv.h +++ b/riscv/insns/vsll_vv.h @@ -1,5 +1,5 @@ // vsll -VI_VV_LOOP +VI_VV_ULOOP ({ vd = vs2 << (vs1 & (sew - 1)); }) diff --git a/riscv/insns/vsll_vx.h b/riscv/insns/vsll_vx.h index 823510b..d669b41 100644 --- a/riscv/insns/vsll_vx.h +++ b/riscv/insns/vsll_vx.h @@ -1,5 +1,5 @@ // vsll -VI_VX_LOOP +VI_VX_ULOOP ({ vd = vs2 << (rs1 & (sew - 1)); }) diff --git a/riscv/insns/vsm3c_vi.h b/riscv/insns/vsm3c_vi.h index b3e8121..f9375a5 100644 --- a/riscv/insns/vsm3c_vi.h +++ b/riscv/insns/vsm3c_vi.h @@ -3,6 +3,7 @@ #include "zvksh_ext_macros.h" require_vsm3_constraints; +VI_CHECK_SSS(false) VI_ZVK_VD_VS2_ZIMM5_EGU32x8_NOVM_LOOP( {}, diff --git a/riscv/insns/vsm3me_vv.h b/riscv/insns/vsm3me_vv.h index dd6cb52..388b79f 100644 --- a/riscv/insns/vsm3me_vv.h +++ b/riscv/insns/vsm3me_vv.h @@ -13,6 +13,7 @@ (ZVKSH_P1((M16) ^ (M9) ^ ZVK_ROL32((M3), 15)) ^ ZVK_ROL32((M13), 7) ^ (M6)) require_vsm3_constraints; +VI_CHECK_SSS(true) VI_ZVK_VD_VS1_VS2_EGU32x8_NOVM_LOOP( {}, diff --git a/riscv/insns/vsm4k_vi.h b/riscv/insns/vsm4k_vi.h index 8f52e68..dd6f67d 100644 --- a/riscv/insns/vsm4k_vi.h +++ b/riscv/insns/vsm4k_vi.h @@ -15,6 +15,7 @@ static constexpr uint32_t zvksed_ck[32] = { }; require_vsm4_constraints; +VI_CHECK_SSS(false) VI_ZVK_VD_VS2_ZIMM5_EGU32x4_NOVM_LOOP( {}, diff --git a/riscv/insns/vsm4r_vs.h b/riscv/insns/vsm4r_vs.h index 44011eb..8db1050 100644 --- a/riscv/insns/vsm4r_vs.h +++ b/riscv/insns/vsm4r_vs.h @@ -3,8 +3,10 @@ #include "zvksed_ext_macros.h" require_vsm4_constraints; +require_align(insn.rd(), P.VU.vflmul); +require_vs2_align_eglmul(128); // No overlap of vd and vs2. -require(insn.rd() != insn.rs2()); +require_noover_eglmul(insn.rd(), insn.rs2()); VI_ZVK_VD_VS2_NOOPERANDS_PRELOOP_EGU32x4_NOVM_LOOP( {}, diff --git a/riscv/insns/vsm4r_vv.h b/riscv/insns/vsm4r_vv.h index 9a18cec..18afee6 100644 --- a/riscv/insns/vsm4r_vv.h +++ b/riscv/insns/vsm4r_vv.h @@ -2,7 +2,9 @@ #include "zvksed_ext_macros.h" + require_vsm4_constraints; +VI_CHECK_SSS(false) VI_ZVK_VD_VS2_EGU32x4_NOVM_LOOP( {}, diff --git a/riscv/insns/vsmul_vv.h b/riscv/insns/vsmul_vv.h index 49e42c1..c1d0a57 100644 --- a/riscv/insns/vsmul_vv.h +++ b/riscv/insns/vsmul_vv.h @@ -1,10 +1,10 @@ // vsmul.vv vd, vs2, vs1 -VRM xrm = P.VU.get_vround_mode(); -int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); -int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); - VI_VV_LOOP ({ + VRM xrm = P.VU.get_vround_mode(); + int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); + int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); + bool overflow = vs1 == vs2 && vs1 == int_min; int128_t result = (int128_t)vs1 * (int128_t)vs2; diff --git a/riscv/insns/vsmul_vx.h b/riscv/insns/vsmul_vx.h index d2724ee..c2e531c 100644 --- a/riscv/insns/vsmul_vx.h +++ b/riscv/insns/vsmul_vx.h @@ -1,10 +1,10 @@ // vsmul.vx vd, vs2, rs1 -VRM xrm = P.VU.get_vround_mode(); -int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); -int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); - VI_VX_LOOP ({ + VRM xrm = P.VU.get_vround_mode(); + int64_t int_max = INT64_MAX >> (64 - P.VU.vsew); + int64_t int_min = INT64_MIN >> (64 - P.VU.vsew); + bool overflow = rs1 == vs2 && rs1 == int_min; int128_t result = (int128_t)rs1 * (int128_t)vs2; diff --git a/riscv/insns/vsra_vi.h b/riscv/insns/vsra_vi.h index 5c58927..4cf616d 100644 --- a/riscv/insns/vsra_vi.h +++ b/riscv/insns/vsra_vi.h @@ -1,5 +1,5 @@ // vsra.vi vd, vs2, zimm5 VI_VI_LOOP ({ - vd = vs2 >> (simm5 & (sew - 1) & 0x1f); + vd = vs2 >> (insn.v_zimm5() & (sew - 1)); }) diff --git a/riscv/insns/vsrl_vi.h b/riscv/insns/vsrl_vi.h index fe5d272..6a3d13c 100644 --- a/riscv/insns/vsrl_vi.h +++ b/riscv/insns/vsrl_vi.h @@ -1,5 +1,5 @@ // vsrl.vi vd, vs2, zimm5 VI_VI_ULOOP ({ - vd = vs2 >> (zimm5 & (sew - 1) & 0x1f); + vd = vs2 >> (zimm5 & (sew - 1)); }) diff --git a/riscv/insns/vssra_vi.h b/riscv/insns/vssra_vi.h index ff2e1c5..12f1240 100644 --- a/riscv/insns/vssra_vi.h +++ b/riscv/insns/vssra_vi.h @@ -1,8 +1,8 @@ -// vssra.vi vd, vs2, simm5 -VRM xrm = P.VU.get_vround_mode(); +// vssra.vi vd, vs2, zimm5 VI_VI_LOOP ({ - int sh = simm5 & (sew - 1) & 0x1f; + VRM xrm = P.VU.get_vround_mode(); + int sh = insn.v_zimm5() & (sew - 1); int128_t val = vs2; INT_ROUNDING(val, xrm, sh); diff --git a/riscv/insns/vssra_vv.h b/riscv/insns/vssra_vv.h index 7bbc766..babca47 100644 --- a/riscv/insns/vssra_vv.h +++ b/riscv/insns/vssra_vv.h @@ -1,7 +1,7 @@ // vssra.vv vd, vs2, vs1 -VRM xrm = P.VU.get_vround_mode(); VI_VV_LOOP ({ + VRM xrm = P.VU.get_vround_mode(); int sh = vs1 & (sew - 1); int128_t val = vs2; diff --git a/riscv/insns/vssra_vx.h b/riscv/insns/vssra_vx.h index 068a22b..3d70726 100644 --- a/riscv/insns/vssra_vx.h +++ b/riscv/insns/vssra_vx.h @@ -1,7 +1,7 @@ // vssra.vx vd, vs2, rs1 -VRM xrm = P.VU.get_vround_mode(); VI_VX_LOOP ({ + VRM xrm = P.VU.get_vround_mode(); int sh = rs1 & (sew - 1); int128_t val = vs2; diff --git a/riscv/insns/vssrl_vi.h b/riscv/insns/vssrl_vi.h index d125164..a2de49e 100644 --- a/riscv/insns/vssrl_vi.h +++ b/riscv/insns/vssrl_vi.h @@ -1,8 +1,8 @@ -// vssra.vi vd, vs2, simm5 -VRM xrm = P.VU.get_vround_mode(); +// vssra.vi vd, vs2, zimm5 VI_VI_ULOOP ({ - int sh = zimm5 & (sew - 1) & 0x1f; + VRM xrm = P.VU.get_vround_mode(); + int sh = zimm5 & (sew - 1); uint128_t val = vs2; INT_ROUNDING(val, xrm, sh); diff --git a/riscv/insns/vssrl_vv.h b/riscv/insns/vssrl_vv.h index a8e5d16..f8924ba 100644 --- a/riscv/insns/vssrl_vv.h +++ b/riscv/insns/vssrl_vv.h @@ -1,7 +1,7 @@ // vssrl.vv vd, vs2, vs1 -VRM xrm = P.VU.get_vround_mode(); VI_VV_ULOOP ({ + VRM xrm = P.VU.get_vround_mode(); int sh = vs1 & (sew - 1); uint128_t val = vs2; diff --git a/riscv/insns/vssrl_vx.h b/riscv/insns/vssrl_vx.h index ee3cb34..04468d5 100644 --- a/riscv/insns/vssrl_vx.h +++ b/riscv/insns/vssrl_vx.h @@ -1,7 +1,7 @@ // vssrl.vx vd, vs2, rs1 -VRM xrm = P.VU.get_vround_mode(); VI_VX_ULOOP ({ + VRM xrm = P.VU.get_vround_mode(); int sh = rs1 & (sew - 1); uint128_t val = vs2; diff --git a/riscv/insns/vwsll_vi.h b/riscv/insns/vwsll_vi.h index 13b5eb4..866cd78 100644 --- a/riscv/insns/vwsll_vi.h +++ b/riscv/insns/vwsll_vi.h @@ -3,6 +3,7 @@ #include "zvk_ext_macros.h" require_zvbb; +VI_CHECK_DSS(false); VI_ZVK_VI_WIDENING_ULOOP({ const reg_t shift = zimm5 & ((2 * sew) - 1); diff --git a/riscv/insns/vwsll_vv.h b/riscv/insns/vwsll_vv.h index 5a64c6c..180fe97 100644 --- a/riscv/insns/vwsll_vv.h +++ b/riscv/insns/vwsll_vv.h @@ -3,6 +3,7 @@ #include "zvk_ext_macros.h" require_zvbb; +VI_CHECK_DSS(true); VI_ZVK_VV_WIDENING_ULOOP({ const reg_t shift = (vs1 & ((2 * sew) - 1)); diff --git a/riscv/insns/vwsll_vx.h b/riscv/insns/vwsll_vx.h index 5264e80..4137d39 100644 --- a/riscv/insns/vwsll_vx.h +++ b/riscv/insns/vwsll_vx.h @@ -3,6 +3,7 @@ #include "zvk_ext_macros.h" require_zvbb; +VI_CHECK_DSS(false); VI_ZVK_VX_WIDENING_ULOOP({ const reg_t shift = (rs1 & ((2 * sew) - 1)); diff --git a/riscv/interactive.cc b/riscv/interactive.cc index b0855fa..9afc718 100644 --- a/riscv/interactive.cc +++ b/riscv/interactive.cc @@ -83,8 +83,7 @@ static void clear_str(bool noncanonical, int fd, std::string target_str) clear_motion += ' '; } clear_motion += '\r'; - if (write(fd, clear_motion.c_str(), clear_motion.size() + 1)) - ; // shut up gcc + (void) write(fd, clear_motion.c_str(), clear_motion.size() + 1); } } @@ -97,8 +96,7 @@ static void send_key(bool noncanonical, int fd, keybuffer_t key_code, const int { key_motion += (char) ((key_code >> (i * BITS_PER_CHAR)) & 0xff); } - if (write(fd, key_motion.c_str(), len) != len) - ; // shut up gcc + (void) write(fd, key_motion.c_str(), len); } } @@ -145,8 +143,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); cursor_pos--; s.erase(cursor_pos, 1); - if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); // move cursor by left arrow key for (unsigned i = 0; i < s.size() - cursor_pos; i++) { send_key(noncanonical, fd, KEYCODE_LEFT, 3); @@ -177,8 +175,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); history_index = std::min(history_commands.size(), history_index + 1); s = history_commands[history_commands.size() - history_index]; - if (noncanonical && write(fd, s.c_str(), s.size() + 1)) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); cursor_pos = s.size(); } key_buffer = 0; @@ -193,8 +191,8 @@ static std::string readline(int fd) } else { s = history_commands[history_commands.size() - history_index]; } - if (noncanonical && write(fd, s.c_str(), s.size() + 1)) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); cursor_pos = s.size(); } key_buffer = 0; @@ -222,14 +220,13 @@ static std::string readline(int fd) key_buffer = 0; break; case KEYCODE_ENTER: - if (noncanonical && write(fd, &ch, 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, &ch, 1); if (s.size() > initial_s_len && (history_commands.size() == 0 || s != history_commands[history_commands.size() - 1])) { history_commands.push_back(s); } return s.substr(initial_s_len); default: - DEFAULT_KEY: // unknown buffered key, do nothing if (key_buffer != 0) { key_buffer = 0; @@ -238,8 +235,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); s.insert(cursor_pos, 1, ch); cursor_pos++; - if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); // send left arrow key to move cursor for (unsigned i = 0; i < s.size() - cursor_pos; i++) { send_key(noncanonical, fd, KEYCODE_LEFT, 3); @@ -342,8 +339,10 @@ void sim_t::interactive() (this->*funcs[cmd])(cmd, args); else out << "Unknown command " << cmd << std::endl; - } catch(trap_t& t) { + } catch(trap_interactive& t) { out << "Bad or missing arguments for command " << cmd << std::endl; + } catch(trap_t& t){ + out << "Received trap: " << t.name() << std::endl; } #ifdef HAVE_BOOST_ASIO if (socketif) @@ -452,37 +451,16 @@ void sim_t::interactive_pc(const std::string& cmd, const std::vector<std::string << zext(get_pc(args), max_xlen) << std::endl; } -static reg_t load(mmu_t* mmu, reg_t addr) { - reg_t val; - - switch (addr % 8) - { - case 0: - val = mmu->load<uint64_t>(addr); - break; - case 4: - val = mmu->load<uint32_t>(addr); - break; - case 2: - case 6: - val = mmu->load<uint16_t>(addr); - break; - default: - val = mmu->load<uint8_t>(addr); - break; - } - return val; -} - reg_t sim_t::get_insn(const std::vector<std::string>& args) { if (args.size() != 1) throw trap_interactive(); processor_t *p = get_core(args[0]); - reg_t addr = p->get_state()->pc; + reg_t pc = p->get_state()->pc; mmu_t* mmu = p->get_mmu(); - return load(mmu, addr); + icache_entry_t* ic_entry = mmu->access_icache(pc); + return ic_entry->data.insn.bits(); } void sim_t::interactive_insn(const std::string& cmd, const std::vector<std::string>& args) @@ -493,9 +471,8 @@ void sim_t::interactive_insn(const std::string& cmd, const std::vector<std::stri processor_t *p = get_core(args[0]); int max_xlen = p->get_isa().get_max_xlen(); - insn_t insn(get_insn(args)); - std::ostream out(sout_.rdbuf()); + insn_t insn(get_insn(args)); // ensure this is outside of ostream to not pollute output on non-interactive trap out << std::hex << std::setfill('0') << "0x" << std::setw(max_xlen/4) << zext(insn.bits(), max_xlen) << " " << p->get_disassembler()->disassemble(insn) << std::endl; } @@ -708,7 +685,24 @@ reg_t sim_t::get_mem(const std::vector<std::string>& args) if (addr == LONG_MAX) addr = strtoul(addr_str.c_str(),NULL,16); - return load(mmu, addr); + reg_t val; + switch (addr % 8) + { + case 0: + val = mmu->load<uint64_t>(addr); + break; + case 4: + val = mmu->load<uint32_t>(addr); + break; + case 2: + case 6: + val = mmu->load<uint16_t>(addr); + break; + default: + val = mmu->load<uint8_t>(addr); + break; + } + return val; } void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::string>& args) @@ -716,8 +710,9 @@ void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::strin int max_xlen = procs[0]->get_isa().get_max_xlen(); std::ostream out(sout_.rdbuf()); + reg_t mem_val = get_mem(args); // ensure this is outside of ostream to not pollute output on non-interactive trap out << std::hex << "0x" << std::setfill('0') << std::setw(max_xlen/4) - << zext(get_mem(args), max_xlen) << std::endl; + << zext(mem_val, max_xlen) << std::endl; } void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args) diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index afb49f2..e99f720 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -23,7 +23,7 @@ typedef enum { EXT_ZCB, EXT_ZCD, EXT_ZCF, - EXT_ZCMLSD, + EXT_ZCLSD, EXT_ZCMP, EXT_ZCMT, EXT_ZKND, @@ -40,6 +40,7 @@ typedef enum { EXT_SMRNMI, EXT_SSCOFPMF, EXT_SVADU, + EXT_SVADE, EXT_SVNAPOT, EXT_SVPBMT, EXT_SVINVAL, @@ -49,6 +50,7 @@ typedef enum { EXT_ZFINX, EXT_ZHINX, EXT_ZHINXMIN, + EXT_ZICCID, EXT_ZICBOM, EXT_ZICBOZ, EXT_ZICNTR, @@ -65,6 +67,7 @@ typedef enum { EXT_ZVKNHB, EXT_ZVKSED, EXT_ZVKSH, + EXT_ZVQDOTQ, EXT_SSTC, EXT_ZAAMO, EXT_ZALRSC, @@ -74,6 +77,8 @@ typedef enum { EXT_INTERNAL_ZFH_MOVE, EXT_SMCSRIND, EXT_SSCSRIND, + EXT_SMCDELEG, + EXT_SSCCFG, EXT_SMCNTRPMF, EXT_ZIMOP, EXT_ZCMOP, @@ -81,6 +86,13 @@ typedef enum { EXT_SSQOSID, EXT_ZICFILP, EXT_ZICFISS, + EXT_SSDBLTRP, + EXT_SMDBLTRP, + EXT_SMMPM, + EXT_SMNPM, + EXT_SSNPM, + EXT_SMAIA, + EXT_SSAIA, NUM_ISA_EXTENSIONS } isa_extension_t; diff --git a/riscv/jtag_dtm.h b/riscv/jtag_dtm.h index 23a54be..bc681de 100644 --- a/riscv/jtag_dtm.h +++ b/riscv/jtag_dtm.h @@ -51,7 +51,9 @@ class jtag_dtm_t // abits must come before dtmcontrol so it can easily be used in the // constructor. - const unsigned abits = 6; + // From RISC-V Debug Spec (both 0.13.2 and 1.0): + // The DMI uses between 7 and 32 address bits. + const unsigned abits = 7; uint32_t dtmcontrol; uint64_t dmi; unsigned bypass; diff --git a/riscv/log_file.h b/riscv/log_file.h index d039859..9e210bb 100644 --- a/riscv/log_file.h +++ b/riscv/log_file.h @@ -31,7 +31,7 @@ public: FILE *get() { return wrapped_file ? wrapped_file.get() : stderr; } private: - std::unique_ptr<FILE, decltype(&fclose)> wrapped_file; + std::unique_ptr<FILE, int(*)(FILE*)> wrapped_file; }; #endif diff --git a/riscv/mmu.cc b/riscv/mmu.cc index d10e23a..30fc47a 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -5,16 +5,16 @@ #include "arith.h" #include "simif.h" #include "processor.h" +#include "decode_macros.h" -mmu_t::mmu_t(simif_t* sim, endianness_t endianness, processor_t* proc) - : sim(sim), proc(proc), +mmu_t::mmu_t(simif_t* sim, endianness_t endianness, processor_t* proc, reg_t cache_blocksz) + : sim(sim), proc(proc), blocksz(cache_blocksz), #ifdef RISCV_ENABLE_DUAL_ENDIAN target_big_endian(endianness == endianness_big), #endif check_triggers_fetch(false), check_triggers_load(false), - check_triggers_store(false), - matched_trigger(NULL) + check_triggers_store(false) { #ifndef RISCV_ENABLE_DUAL_ENDIAN assert(endianness == endianness_little); @@ -35,9 +35,9 @@ void mmu_t::flush_icache() void mmu_t::flush_tlb() { - memset(tlb_insn_tag, -1, sizeof(tlb_insn_tag)); - memset(tlb_load_tag, -1, sizeof(tlb_load_tag)); - memset(tlb_store_tag, -1, sizeof(tlb_store_tag)); + memset(tlb_insn, -1, sizeof(tlb_insn)); + memset(tlb_load, -1, sizeof(tlb_load)); + memset(tlb_store, -1, sizeof(tlb_store)); flush_icache(); } @@ -54,7 +54,7 @@ void throw_access_exception(bool virt, reg_t addr, access_type type) reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len) { - reg_t addr = access_info.vaddr; + reg_t addr = access_info.transformed_vaddr; access_type type = access_info.type; if (!proc) return addr; @@ -64,33 +64,51 @@ reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len) reg_t paddr = walk(access_info) | (addr & (PGSIZE-1)); if (!pmp_ok(paddr, len, access_info.flags.ss_access ? STORE : type, mode, access_info.flags.hlvx)) - throw_access_exception(virt, addr, type); + throw_access_exception(virt, addr, access_info.flags.ss_access ? STORE : type); return paddr; } -tlb_entry_t mmu_t::fetch_slow_path(reg_t vaddr) +inline mmu_t::insn_parcel_t mmu_t::perform_intrapage_fetch(reg_t vaddr, uintptr_t host_addr, reg_t paddr) { + insn_parcel_t res; + + if (host_addr) + memcpy(&res, (char*)host_addr, sizeof(res)); + else if (!mmio_fetch(paddr, sizeof(res), (uint8_t*)&res)) + throw trap_instruction_access_fault(proc->state.v, vaddr, 0, 0); + + return res; +} + +mmu_t::insn_parcel_t mmu_t::fetch_slow_path(reg_t vaddr) +{ + if (matched_trigger) { + auto trig = matched_trigger.value(); + matched_trigger.reset(); + throw trig; + } + + if (auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_insn, vaddr, TLB_FLAGS & ~TLB_CHECK_TRIGGERS); tlb_hit) { + // Fast path for simple cases + return perform_intrapage_fetch(vaddr, host_addr, paddr); + } + + auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_insn, vaddr, TLB_FLAGS); auto access_info = generate_access_info(vaddr, FETCH, {}); check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt); - tlb_entry_t result; - reg_t vpn = vaddr >> PGSHIFT; - if (unlikely(tlb_insn_tag[vpn % TLB_ENTRIES] != (vpn | TLB_CHECK_TRIGGERS))) { - reg_t paddr = translate(access_info, sizeof(fetch_temp)); - if (auto host_addr = sim->addr_to_mem(paddr)) { - result = refill_tlb(vaddr, paddr, host_addr, FETCH); - } else { - if (!mmio_fetch(paddr, sizeof fetch_temp, (uint8_t*)&fetch_temp)) - throw trap_instruction_access_fault(proc->state.v, vaddr, 0, 0); - result = {(char*)&fetch_temp - vaddr, paddr - vaddr}; - } - } else { - result = tlb_data[vpn % TLB_ENTRIES]; + if (!tlb_hit) { + paddr = translate(access_info, sizeof(insn_parcel_t)); + host_addr = (uintptr_t)sim->addr_to_mem(paddr); + + refill_tlb(vaddr, paddr, (char*)host_addr, FETCH); } - check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt, from_le(*(const uint16_t*)(result.host_offset + vaddr))); + auto res = perform_intrapage_fetch(vaddr, host_addr, paddr); + + check_triggers(triggers::OPERATION_EXECUTE, vaddr, access_info.effective_virt, from_le(res)); - return result; + return res; } reg_t reg_from_bytes(size_t len, const uint8_t* bytes) @@ -122,7 +140,8 @@ reg_t reg_from_bytes(size_t len, const uint8_t* bytes) bool mmu_t::mmio_ok(reg_t paddr, access_type UNUSED type) { // Disallow access to debug region when not in debug mode - if (paddr >= DEBUG_START && paddr <= DEBUG_END && proc && !proc->state.debug_mode) + static_assert(DEBUG_START == 0); + if (/* paddr >= DEBUG_START && */ paddr <= DEBUG_END && proc && !proc->state.debug_mode) return false; return true; @@ -183,160 +202,210 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool case triggers::TIMING_AFTER: // We want to take this exception on the next instruction. We check - // whether to do so in the I$ refill path, so flush the I$. - flush_icache(); - matched_trigger = new triggers::matched_t(operation, tval, match->action, virt); + // whether to do so in the I$ refill slow path, which we can force by + // flushing the TLB. + flush_tlb(); + matched_trigger = triggers::matched_t(operation, tval, match->action, virt); } } -void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_t access_info) +inline void mmu_t::perform_intrapage_load(reg_t vaddr, uintptr_t host_addr, reg_t paddr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags) { - reg_t addr = access_info.vaddr; - reg_t vpn = addr >> PGSHIFT; - if (!access_info.flags.is_special_access() && vpn == (tlb_load_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) { - auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; - memcpy(bytes, host_addr, len); - return; + if (host_addr) { + memcpy(bytes, (char*)host_addr, len); + } else if (!mmio_load(paddr, len, bytes)) { + auto access_info = generate_access_info(vaddr, LOAD, xlate_flags); + if (access_info.flags.ss_access) + throw trap_store_access_fault(access_info.effective_virt, access_info.transformed_vaddr, 0, 0); + else + throw trap_load_access_fault(access_info.effective_virt, access_info.transformed_vaddr, 0, 0); } - reg_t paddr = translate(access_info, len); + if (tracer.interested_in_range(paddr, paddr + len, LOAD)) + tracer.trace(paddr, len, LOAD); +} - if (access_info.flags.lr && !sim->reservable(paddr)) { - throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0); - } +void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_t access_info) +{ + reg_t vaddr = access_info.vaddr; + auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_load, vaddr, TLB_FLAGS); + if (!tlb_hit || access_info.flags.is_special_access()) { + paddr = translate(access_info, len); + host_addr = (uintptr_t)sim->addr_to_mem(paddr); - if (auto host_addr = sim->addr_to_mem(paddr)) { - memcpy(bytes, host_addr, len); - if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) - tracer.trace(paddr, len, LOAD); - else if (!access_info.flags.is_special_access()) - refill_tlb(addr, paddr, host_addr, LOAD); + if (!access_info.flags.is_special_access()) + refill_tlb(vaddr, paddr, (char*)host_addr, LOAD); - } else if (!mmio_load(paddr, len, bytes)) { - throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0); + if (access_info.flags.lr && !sim->reservable(paddr)) { + throw trap_load_access_fault(access_info.effective_virt, access_info.transformed_vaddr, 0, 0); + } } + perform_intrapage_load(vaddr, host_addr, paddr, len, bytes, access_info.flags); + if (access_info.flags.lr) { load_reservation_address = paddr; } } -void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags) +void mmu_t::load_slow_path(reg_t original_addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags) { - auto access_info = generate_access_info(addr, LOAD, xlate_flags); - check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt); + if (likely(!xlate_flags.is_special_access())) { + // Fast path for simple cases + auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_load, original_addr, TLB_FLAGS & ~TLB_CHECK_TRIGGERS); + bool intrapage = (original_addr % PGSIZE) + len <= PGSIZE; + bool aligned = (original_addr & (len - 1)) == 0; + + if (likely(tlb_hit && (aligned || (intrapage && is_misaligned_enabled())))) { + return perform_intrapage_load(original_addr, host_addr, paddr, len, bytes, xlate_flags); + } + } - if ((addr & (len - 1)) == 0) { + auto access_info = generate_access_info(original_addr, LOAD, xlate_flags); + reg_t transformed_addr = access_info.transformed_vaddr; + check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt); + + if ((transformed_addr & (len - 1)) == 0) { load_slow_path_intrapage(len, bytes, access_info); } else { bool gva = access_info.effective_virt; if (!is_misaligned_enabled()) - throw trap_load_address_misaligned(gva, addr, 0, 0); + throw trap_load_address_misaligned(gva, transformed_addr, 0, 0); if (access_info.flags.lr) - throw trap_load_access_fault(gva, addr, 0, 0); + throw trap_load_access_fault(gva, transformed_addr, 0, 0); - reg_t len_page0 = std::min(len, PGSIZE - addr % PGSIZE); + reg_t len_page0 = std::min(len, PGSIZE - transformed_addr % PGSIZE); load_slow_path_intrapage(len_page0, bytes, access_info); - if (len_page0 != len) - load_slow_path_intrapage(len - len_page0, bytes + len_page0, access_info.split_misaligned_access(len_page0)); + if (len_page0 != len) { + auto tail_access_info = generate_access_info(original_addr + len_page0, LOAD, xlate_flags); + load_slow_path_intrapage(len - len_page0, bytes + len_page0, tail_access_info); + } } while (len > sizeof(reg_t)) { - check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), bytes)); + check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), bytes)); len -= sizeof(reg_t); bytes += sizeof(reg_t); } - check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt, reg_from_bytes(len, bytes)); + check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(len, bytes)); + + if (proc && unlikely(proc->get_log_commits_enabled())) + proc->state.log_mem_read.push_back(std::make_tuple(original_addr, 0, len)); } -void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_access_info_t access_info, bool actually_store) +inline void mmu_t::perform_intrapage_store(reg_t vaddr, uintptr_t host_addr, reg_t paddr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags) { - reg_t addr = access_info.vaddr; - reg_t vpn = addr >> PGSHIFT; - if (!access_info.flags.is_special_access() && vpn == (tlb_store_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) { - if (actually_store) { - auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; - memcpy(host_addr, bytes, len); - } - return; + if (host_addr) { + memcpy((char*)host_addr, bytes, len); + } else if (!mmio_store(paddr, len, bytes)) { + auto access_info = generate_access_info(vaddr, STORE, xlate_flags); + throw trap_store_access_fault(access_info.effective_virt, access_info.transformed_vaddr, 0, 0); } - reg_t paddr = translate(access_info, len); + if (tracer.interested_in_range(paddr, paddr + len, STORE)) + tracer.trace(paddr, len, STORE); +} - if (actually_store) { - if (auto host_addr = sim->addr_to_mem(paddr)) { - memcpy(host_addr, bytes, len); - if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) - tracer.trace(paddr, len, STORE); - else if (!access_info.flags.is_special_access()) - refill_tlb(addr, paddr, host_addr, STORE); - } else if (!mmio_store(paddr, len, bytes)) { - throw trap_store_access_fault(access_info.effective_virt, addr, 0, 0); - } +void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_access_info_t access_info, bool actually_store) +{ + reg_t vaddr = access_info.vaddr; + auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_store, vaddr, TLB_FLAGS); + if (!tlb_hit || access_info.flags.is_special_access()) { + paddr = translate(access_info, len); + host_addr = (uintptr_t)sim->addr_to_mem(paddr); + + if (!access_info.flags.is_special_access()) + refill_tlb(vaddr, paddr, (char*)host_addr, STORE); } + + if (actually_store) + perform_intrapage_store(vaddr, host_addr, paddr, len, bytes, access_info.flags); } -void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment) +void mmu_t::store_slow_path(reg_t original_addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment) { - auto access_info = generate_access_info(addr, STORE, xlate_flags); + if (likely(!xlate_flags.is_special_access())) { + // Fast path for simple cases + auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_store, original_addr, TLB_FLAGS & ~TLB_CHECK_TRIGGERS); + bool intrapage = (original_addr % PGSIZE) + len <= PGSIZE; + bool aligned = (original_addr & (len - 1)) == 0; + + if (likely(tlb_hit && (aligned || (intrapage && is_misaligned_enabled())))) { + if (actually_store) + perform_intrapage_store(original_addr, host_addr, paddr, len, bytes, xlate_flags); + return; + } + } + + auto access_info = generate_access_info(original_addr, STORE, xlate_flags); + reg_t transformed_addr = access_info.transformed_vaddr; if (actually_store) { reg_t trig_len = len; const uint8_t* trig_bytes = bytes; while (trig_len > sizeof(reg_t)) { - check_triggers(triggers::OPERATION_STORE, addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), trig_bytes)); + check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), trig_bytes)); trig_len -= sizeof(reg_t); trig_bytes += sizeof(reg_t); } - check_triggers(triggers::OPERATION_STORE, addr, access_info.effective_virt, reg_from_bytes(trig_len, trig_bytes)); + check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(trig_len, trig_bytes)); } - if (addr & (len - 1)) { + if (transformed_addr & (len - 1)) { bool gva = access_info.effective_virt; if (!is_misaligned_enabled()) - throw trap_store_address_misaligned(gva, addr, 0, 0); + throw trap_store_address_misaligned(gva, transformed_addr, 0, 0); if (require_alignment) - throw trap_store_access_fault(gva, addr, 0, 0); + throw trap_store_access_fault(gva, transformed_addr, 0, 0); - reg_t len_page0 = std::min(len, PGSIZE - addr % PGSIZE); + reg_t len_page0 = std::min(len, PGSIZE - transformed_addr % PGSIZE); store_slow_path_intrapage(len_page0, bytes, access_info, actually_store); - if (len_page0 != len) - store_slow_path_intrapage(len - len_page0, bytes + len_page0, access_info.split_misaligned_access(len_page0), actually_store); + if (len_page0 != len) { + auto tail_access_info = generate_access_info(original_addr + len_page0, STORE, xlate_flags); + store_slow_path_intrapage(len - len_page0, bytes + len_page0, tail_access_info, actually_store); + } } else { store_slow_path_intrapage(len, bytes, access_info, actually_store); } + + if (actually_store && proc && unlikely(proc->get_log_commits_enabled())) + proc->state.log_mem_write.push_back(std::make_tuple(original_addr, reg_from_bytes(len, bytes), len)); } tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type) { reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES; reg_t expected_tag = vaddr >> PGSHIFT; + reg_t base_paddr = paddr & ~reg_t(PGSIZE - 1); - tlb_entry_t entry = {host_addr - vaddr, paddr - vaddr}; + tlb_entry_t entry = {uintptr_t(host_addr) - (vaddr % PGSIZE), paddr - (vaddr % PGSIZE)}; - if (in_mprv()) + if (in_mprv() + || !pmp_homogeneous(base_paddr, PGSIZE) + || (proc && proc->get_log_commits_enabled())) return entry; - if ((tlb_load_tag[idx] & ~TLB_CHECK_TRIGGERS) != expected_tag) - tlb_load_tag[idx] = -1; - if ((tlb_store_tag[idx] & ~TLB_CHECK_TRIGGERS) != expected_tag) - tlb_store_tag[idx] = -1; - if ((tlb_insn_tag[idx] & ~TLB_CHECK_TRIGGERS) != expected_tag) - tlb_insn_tag[idx] = -1; - - if ((check_triggers_fetch && type == FETCH) || - (check_triggers_load && type == LOAD) || - (check_triggers_store && type == STORE)) - expected_tag |= TLB_CHECK_TRIGGERS; - - if (pmp_homogeneous(paddr & ~reg_t(PGSIZE - 1), PGSIZE)) { - if (type == FETCH) tlb_insn_tag[idx] = expected_tag; - else if (type == STORE) tlb_store_tag[idx] = expected_tag; - else tlb_load_tag[idx] = expected_tag; + auto trace_flag = tracer.interested_in_range(base_paddr, base_paddr + PGSIZE, type) ? TLB_CHECK_TRACER : 0; + auto mmio_flag = host_addr ? 0 : TLB_MMIO; + + switch (type) { + case FETCH: + tlb_insn[idx].data = entry; + tlb_insn[idx].tag = expected_tag | (check_triggers_fetch ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag; + break; + case LOAD: + tlb_load[idx].data = entry; + tlb_load[idx].tag = expected_tag | (check_triggers_load ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag; + break; + case STORE: + tlb_store[idx].data = entry; + tlb_store[idx].tag = expected_tag | (check_triggers_store ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag; + break; + default: + abort(); } - tlb_data[idx] = entry; return entry; } @@ -399,7 +468,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty int maxgpabits = vm.levels * vm.idxbits + vm.widenbits + PGSHIFT; reg_t maxgpa = (1ULL << maxgpabits) - 1; - bool mxr = proc->state.sstatus->readvirt(false) & MSTATUS_MXR; + bool mxr = !is_for_vs_pt_addr && (proc->state.sstatus->readvirt(false) & MSTATUS_MXR); // tinst is set to 0x3000/0x3020 - for RV64 read/write respectively for // VS-stage address translation (for spike HSXLEN == VSXLEN always) else // tinst is set to 0x2000/0x2020 - for RV32 read/write respectively for @@ -422,6 +491,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; bool pbmte = proc->get_state()->menvcfg->read() & MENVCFG_PBMTE; bool hade = proc->get_state()->menvcfg->read() & MENVCFG_ADUE; + int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); if (pte & PTE_RSVD) { break; @@ -437,6 +507,8 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty base = ppn << PGSHIFT; } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { break; + } else if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) { + break; } else if (!(pte & PTE_U)) { break; } else if (type == FETCH || hlvx ? !(pte & PTE_X) : @@ -461,10 +533,6 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty reg_t vpn = gpa >> PGSHIFT; reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; - int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); - if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) - break; - reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) | (vpn & ((reg_t(1) << napot_bits) - 1)) | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; @@ -484,7 +552,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty reg_t mmu_t::walk(mem_access_info_t access_info) { access_type type = access_info.type; - reg_t addr = access_info.vaddr; + reg_t addr = access_info.transformed_vaddr; bool virt = access_info.effective_virt; bool hlvx = access_info.flags.hlvx; reg_t mode = access_info.effective_priv; @@ -496,7 +564,7 @@ reg_t mmu_t::walk(mem_access_info_t access_info) if (ss_access) { if (vm.levels == 0) - trap_store_access_fault(virt, addr, 0, 0); + throw trap_store_access_fault(virt, addr, 0, 0); type = STORE; } @@ -526,6 +594,8 @@ reg_t mmu_t::walk(mem_access_info_t access_info) bool pbmte = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_PBMTE) : (proc->get_state()->menvcfg->read() & MENVCFG_PBMTE); bool hade = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_ADUE) : (proc->get_state()->menvcfg->read() & MENVCFG_ADUE); bool sse = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_SSE) : (proc->get_state()->menvcfg->read() & MENVCFG_SSE); + bool ss_page = !(pte & PTE_R) && (pte & PTE_W) && !(pte & PTE_X); + int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); if (pte & PTE_RSVD) { break; @@ -547,21 +617,23 @@ reg_t mmu_t::walk(mem_access_info_t access_info) // not shadow stack access xwr=110 or xwr=010 page cause page fault // shadow stack access with PTE_X moved to following check break; - } else if ((!(pte & PTE_R) && (pte & PTE_W) && !(pte & PTE_X)) && (type == STORE && !ss_access)) { - // not shadow stack store and xwr = 010 cause access-fault + } else if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) { + break; + } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { + break; + } else if (ss_page && ((type == STORE && !ss_access) || access_info.flags.clean_inval)) { + // non-shadow-stack store or CBO with xwr = 010 causes access-fault throw trap_store_access_fault(virt, addr, 0, 0); - } else if ((!(pte & PTE_R) && (pte & PTE_W) && !(pte & PTE_X)) && type == FETCH) { + } else if (ss_page && type == FETCH) { // fetch from shadow stack pages cause instruction access-fault throw trap_instruction_access_fault(virt, addr, 0, 0); } else if ((((pte & PTE_R) && (pte & PTE_W)) || (pte & PTE_X)) && ss_access) { // shadow stack access cause store access fault if xwr!=010 and xwr!=001 throw trap_store_access_fault(virt, addr, 0, 0); } else if (type == FETCH || hlvx ? !(pte & PTE_X) : - type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : + type == LOAD ? !(sse && ss_page) && !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : !(pte & PTE_W)) { break; - } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { - break; } else { reg_t ad = PTE_A | ((type == STORE) * PTE_D); @@ -581,10 +653,6 @@ reg_t mmu_t::walk(mem_access_info_t access_info) // for superpage or Svnapot NAPOT mappings, make a fake leaf PTE for the TLB's benefit. reg_t vpn = addr >> PGSHIFT; - int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); - if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) - break; - reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) | (vpn & ((reg_t(1) << napot_bits) - 1)) | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; @@ -606,3 +674,55 @@ void mmu_t::register_memtracer(memtracer_t* t) flush_tlb(); tracer.hook(t); } + +reg_t mmu_t::get_pmlen(bool effective_virt, reg_t effective_priv, xlate_flags_t flags) const { + if (!proc || proc->get_xlen() != 64 || flags.hlvx) + return 0; + + reg_t pmm = 0; + if (effective_priv == PRV_M) + pmm = get_field(proc->state.mseccfg->read(), MSECCFG_PMM); + else if ((proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(effective_virt)) & MSTATUS_MXR) + pmm = 0; + else if (!effective_virt && (effective_priv == PRV_S || (!proc->extension_enabled('S') && effective_priv == PRV_U))) + pmm = get_field(proc->state.menvcfg->read(), MENVCFG_PMM); + else if (effective_virt && effective_priv == PRV_S) + pmm = get_field(proc->state.henvcfg->read(), HENVCFG_PMM); + else if (proc->state.prv == PRV_U && flags.forced_virt) + pmm = get_field(proc->state.hstatus->read(), HSTATUS_HUPMM); + else if (effective_priv == PRV_U) + pmm = get_field(proc->state.senvcfg->read(), SENVCFG_PMM); + else + assert(false); + + switch (pmm) { + case 2: return 7; + case 3: return 16; + } + return 0; +} + +mem_access_info_t mmu_t::generate_access_info(reg_t addr, access_type type, xlate_flags_t xlate_flags) { + if (!proc) + return {addr, addr, 0, false, {}, type}; + bool virt = proc->state.v; + reg_t mode = proc->state.prv; + reg_t transformed_addr = addr; + if (type != FETCH) { + if (in_mprv()) { + mode = get_field(proc->state.mstatus->read(), MSTATUS_MPP); + if (get_field(proc->state.mstatus->read(), MSTATUS_MPV) && mode != PRV_M) + virt = true; + } + if (xlate_flags.forced_virt) { + virt = true; + mode = get_field(proc->state.hstatus->read(), HSTATUS_SPVP); + } + auto xlen = proc->get_const_xlen(); + reg_t pmlen = get_pmlen(virt, mode, xlate_flags); + reg_t satp = proc->state.satp->readvirt(virt); + bool is_physical_addr = mode == PRV_M || get_field(satp, SATP64_MODE) == SATP_MODE_OFF; + transformed_addr = is_physical_addr ? zext(addr, xlen - pmlen) : sext(addr, xlen - pmlen); + } + return {addr, transformed_addr, mode, virt, xlate_flags, type}; +} diff --git a/riscv/mmu.h b/riscv/mmu.h index 3e4ae9a..94f3a97 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -18,8 +18,22 @@ // virtual memory configuration #define PGSHIFT 12 const reg_t PGSIZE = 1 << PGSHIFT; -const reg_t PGMASK = ~(PGSIZE-1); -#define MAX_PADDR_BITS 56 // imposed by Sv39 / Sv48 +#define MAX_PADDR_BITS 64 + +// observability hooks for load, store and fetch +// intentionally empty not to cause runtime overhead +// can be redefined if needed +#ifndef MMU_OBSERVE_FETCH +#define MMU_OBSERVE_FETCH(addr, insn, length) +#endif + +#ifndef MMU_OBSERVE_LOAD +#define MMU_OBSERVE_LOAD(addr, data, length) +#endif + +#ifndef MMU_OBSERVE_STORE +#define MMU_OBSERVE_STORE(addr, data, length) +#endif struct insn_fetch_t { @@ -34,8 +48,13 @@ struct icache_entry_t { }; struct tlb_entry_t { - char* host_offset; - reg_t target_offset; + uintptr_t host_addr; + reg_t target_addr; +}; + +struct dtlb_entry_t { + tlb_entry_t data; + reg_t tag; }; struct xlate_flags_t { @@ -43,22 +62,20 @@ struct xlate_flags_t { const bool hlvx : 1 {false}; const bool lr : 1 {false}; const bool ss_access : 1 {false}; + const bool clean_inval : 1 {false}; bool is_special_access() const { - return forced_virt || hlvx || lr || ss_access; + return forced_virt || hlvx || lr || ss_access || clean_inval; } }; struct mem_access_info_t { const reg_t vaddr; + const reg_t transformed_vaddr; const reg_t effective_priv; const bool effective_virt; const xlate_flags_t flags; const access_type type; - - mem_access_info_t split_misaligned_access(reg_t offset) const { - return {vaddr + offset, effective_priv, effective_virt, flags, type}; - } }; void throw_access_exception(bool virt, reg_t addr, access_type type); @@ -68,47 +85,26 @@ void throw_access_exception(bool virt, reg_t addr, access_type type); class mmu_t { private: - std::map<reg_t, reg_t> alloc_cache; - std::vector<std::pair<reg_t, reg_t >> addr_tbl; - - mem_access_info_t generate_access_info(reg_t addr, access_type type, xlate_flags_t xlate_flags) { - if (!proc) - return {addr, 0, false, {}, type}; - bool virt = proc->state.v; - reg_t mode = proc->state.prv; - if (type != FETCH) { - if (in_mprv()) { - mode = get_field(proc->state.mstatus->read(), MSTATUS_MPP); - if (get_field(proc->state.mstatus->read(), MSTATUS_MPV) && mode != PRV_M) - virt = true; - } - if (xlate_flags.forced_virt) { - virt = true; - mode = get_field(proc->state.hstatus->read(), HSTATUS_SPVP); - } - } - return {addr, mode, virt, xlate_flags, type}; - } + reg_t get_pmlen(bool effective_virt, reg_t effective_priv, xlate_flags_t flags) const; + mem_access_info_t generate_access_info(reg_t addr, access_type type, xlate_flags_t xlate_flags); public: - mmu_t(simif_t* sim, endianness_t endianness, processor_t* proc); + mmu_t(simif_t* sim, endianness_t endianness, processor_t* proc, reg_t cache_blocksz); ~mmu_t(); template<typename T> T ALWAYS_INLINE load(reg_t addr, xlate_flags_t xlate_flags = {}) { target_endian<T> res; - reg_t vpn = addr >> PGSHIFT; bool aligned = (addr & (sizeof(T) - 1)) == 0; - bool tlb_hit = tlb_load_tag[vpn % TLB_ENTRIES] == vpn; + auto [tlb_hit, host_addr, _] = access_tlb(tlb_load, addr); if (likely(!xlate_flags.is_special_access() && aligned && tlb_hit)) { - res = *(target_endian<T>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); + res = *(target_endian<T>*)host_addr; } else { load_slow_path(addr, sizeof(T), (uint8_t*)&res, xlate_flags); } - if (unlikely(proc && proc->get_log_commits_enabled())) - proc->state.log_mem_read.push_back(std::make_tuple(addr, 0, sizeof(T))); + MMU_OBSERVE_LOAD(addr,from_target(res),sizeof(T)); return from_target(res); } @@ -138,19 +134,16 @@ public: template<typename T> void ALWAYS_INLINE store(reg_t addr, T val, xlate_flags_t xlate_flags = {}) { - reg_t vpn = addr >> PGSHIFT; + MMU_OBSERVE_STORE(addr, val, sizeof(T)); bool aligned = (addr & (sizeof(T) - 1)) == 0; - bool tlb_hit = tlb_store_tag[vpn % TLB_ENTRIES] == vpn; + auto [tlb_hit, host_addr, _] = access_tlb(tlb_store, addr); if (!xlate_flags.is_special_access() && likely(aligned && tlb_hit)) { - *(target_endian<T>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); + *(target_endian<T>*)host_addr = to_target(val); } else { target_endian<T> target_val = to_target(val); store_slow_path(addr, sizeof(T), (const uint8_t*)&target_val, xlate_flags, true, false); } - - if (unlikely(proc && proc->get_log_commits_enabled())) - proc->state.log_mem_write.push_back(std::make_tuple(addr, val, sizeof(T))); } template<typename T> @@ -232,28 +225,37 @@ public: throw trap_load_address_misaligned((proc) ? proc->state.v : false, addr, 0, 0); } - return (float128_t){load<uint64_t>(addr), load<uint64_t>(addr + 8)}; + float128_t res; + res.v[0] = load<uint64_t>(addr); + res.v[1] = load<uint64_t>(addr + 8); + return res; } void cbo_zero(reg_t addr) { - auto base = addr & ~(blocksz - 1); + auto access_info = generate_access_info(addr, STORE, {}); + reg_t transformed_addr = access_info.transformed_vaddr; + + auto base = transformed_addr & ~(blocksz - 1); for (size_t offset = 0; offset < blocksz; offset += 1) { - check_triggers(triggers::OPERATION_STORE, base + offset, false, addr, std::nullopt); + check_triggers(triggers::OPERATION_STORE, base + offset, false, transformed_addr, std::nullopt); store<uint8_t>(base + offset, 0); } } void clean_inval(reg_t addr, bool clean, bool inval) { - auto base = addr & ~(blocksz - 1); + auto access_info = generate_access_info(addr, LOAD, {.clean_inval = true}); + reg_t transformed_addr = access_info.transformed_vaddr; + + auto base = transformed_addr & ~(blocksz - 1); for (size_t offset = 0; offset < blocksz; offset += 1) - check_triggers(triggers::OPERATION_STORE, base + offset, false, addr, std::nullopt); + check_triggers(triggers::OPERATION_STORE, base + offset, false, transformed_addr, std::nullopt); convert_load_traps_to_store_traps({ - const reg_t paddr = translate(generate_access_info(addr, LOAD, {}), 1); + const reg_t paddr = translate(access_info, 1); if (sim->reservable(paddr)) { if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) tracer.clean_invalidate(paddr, blocksz, clean, inval); } else { - throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0); + throw trap_store_access_fault((proc) ? proc->state.v : false, transformed_addr, 0, 0); } }) } @@ -299,31 +301,32 @@ public: template<typename T> T ALWAYS_INLINE fetch_jump_table(reg_t addr) { - auto tlb_entry = translate_insn_addr(addr); - return from_target(*(target_endian<T>*)(tlb_entry.host_offset + addr)); + T res = 0; + for (size_t i = 0; i < sizeof(T) / sizeof(insn_parcel_t); i++) + res |= (T)fetch_insn_parcel(addr + i * sizeof(insn_parcel_t)) << (i * sizeof(insn_parcel_t) * 8); + + // table accesses use data endianness, not instruction (little) endianness + return target_big_endian ? to_be(res) : res; } inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry) { - if (matched_trigger) - throw *matched_trigger; + insn_bits_t insn = fetch_insn_parcel(addr); - auto tlb_entry = translate_insn_addr(addr); - insn_bits_t insn = from_le(*(uint16_t*)(tlb_entry.host_offset + addr)); int length = insn_length(insn); if (likely(length == 4)) { - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 2)) << 16; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 2) << 16; } else if (length == 2) { // entire instruction already fetched } else if (length == 6) { - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 2)) << 16; - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 2) << 16; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 4) << 32; } else { static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t"); - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 2)) << 16; - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 6)) << 48; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 2) << 16; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 4) << 32; + insn |= (insn_bits_t)fetch_insn_parcel(addr + 6) << 48; } insn_fetch_t fetch = {proc->decode_insn(insn), insn}; @@ -331,19 +334,24 @@ public: entry->next = &icache[icache_index(addr + length)]; entry->data = fetch; - reg_t paddr = tlb_entry.target_offset + addr;; - if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) { - entry->tag = -1; - tracer.trace(paddr, length, FETCH); + auto [check_tracer, _, paddr] = access_tlb(tlb_insn, addr, TLB_FLAGS, TLB_CHECK_TRACER); + if (unlikely(check_tracer)) { + if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) { + entry->tag = -1; + tracer.trace(paddr, paddr + length, FETCH); + } } + MMU_OBSERVE_FETCH(addr, insn, length); return entry; } inline icache_entry_t* access_icache(reg_t addr) { icache_entry_t* entry = &icache[icache_index(addr)]; - if (likely(entry->tag == addr)) + if (likely(entry->tag == addr)){ + MMU_OBSERVE_FETCH(addr, entry->data.insn, insn_length(entry->data.insn.bits())); return entry; + } return refill_icache(addr, entry); } @@ -353,6 +361,17 @@ public: return refill_icache(addr, &entry)->data; } + std::tuple<bool, uintptr_t, reg_t> ALWAYS_INLINE access_tlb(const dtlb_entry_t* tlb, reg_t vaddr, reg_t allowed_flags = 0, reg_t required_flags = 0) + { + auto vpn = vaddr / PGSIZE, pgoff = vaddr % PGSIZE; + auto& entry = tlb[vpn % TLB_ENTRIES]; + auto hit = likely((entry.tag & (~allowed_flags | required_flags)) == (vpn | required_flags)); + bool mmio = allowed_flags & TLB_MMIO & entry.tag; + auto host_addr = mmio ? 0 : entry.data.host_addr + pgoff; + auto paddr = entry.data.target_addr + pgoff; + return std::make_tuple(hit, host_addr, paddr); + } + void flush_tlb(); void flush_icache(); @@ -378,17 +397,11 @@ public: return target_big_endian? target_endian<T>::to_be(n) : target_endian<T>::to_le(n); } - void set_cache_blocksz(reg_t size) - { - blocksz = size; - } - private: simif_t* sim; processor_t* proc; memtracer_list_t tracer; reg_t load_reservation_address; - uint16_t fetch_temp; reg_t blocksz; // implement an instruction cache for simulator performance @@ -399,10 +412,12 @@ private: // If a TLB tag has TLB_CHECK_TRIGGERS set, then the MMU must check for a // trigger match before completing an access. static const reg_t TLB_CHECK_TRIGGERS = reg_t(1) << 63; - tlb_entry_t tlb_data[TLB_ENTRIES]; - reg_t tlb_insn_tag[TLB_ENTRIES]; - reg_t tlb_load_tag[TLB_ENTRIES]; - reg_t tlb_store_tag[TLB_ENTRIES]; + static const reg_t TLB_CHECK_TRACER = reg_t(1) << 62; + static const reg_t TLB_MMIO = reg_t(1) << 61; + static const reg_t TLB_FLAGS = TLB_CHECK_TRIGGERS | TLB_CHECK_TRACER | TLB_MMIO; + dtlb_entry_t tlb_load[TLB_ENTRIES]; + dtlb_entry_t tlb_store[TLB_ENTRIES]; + dtlb_entry_t tlb_insn[TLB_ENTRIES]; // finish translation on a TLB miss and update the TLB tlb_entry_t refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type); @@ -415,11 +430,15 @@ private: reg_t walk(mem_access_info_t access_info); // handle uncommon cases: TLB misses, page faults, MMIO - tlb_entry_t fetch_slow_path(reg_t addr); - void load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags); + typedef uint16_t insn_parcel_t; + insn_parcel_t fetch_slow_path(reg_t addr); + insn_parcel_t perform_intrapage_fetch(reg_t vaddr, uintptr_t host_addr, reg_t paddr); + void load_slow_path(reg_t original_addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags); void load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_t access_info); - void store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool require_alignment); + void perform_intrapage_load(reg_t vaddr, uintptr_t host_addr, reg_t paddr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags); + void store_slow_path(reg_t original_addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool require_alignment); void store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_access_info_t access_info, bool actually_store); + void perform_intrapage_store(reg_t vaddr, uintptr_t host_addr, reg_t paddr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags); bool mmio_fetch(reg_t paddr, size_t len, uint8_t* bytes); bool mmio_load(reg_t paddr, size_t len, uint8_t* bytes); bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes); @@ -478,23 +497,18 @@ private: } } - // ITLB lookup - inline tlb_entry_t translate_insn_addr(reg_t addr) { - reg_t vpn = addr >> PGSHIFT; - if (likely(tlb_insn_tag[vpn % TLB_ENTRIES] == vpn)) - return tlb_data[vpn % TLB_ENTRIES]; - return fetch_slow_path(addr); - } + inline insn_parcel_t fetch_insn_parcel(reg_t addr) { + if (auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_insn, addr); tlb_hit) + return from_le(*(insn_parcel_t*)host_addr); - inline const uint16_t* translate_insn_addr_to_host(reg_t addr) { - return (uint16_t*)(translate_insn_addr(addr).host_offset + addr); + return from_le(fetch_slow_path(addr)); } - inline bool in_mprv() + inline bool in_mprv() const { return proc != nullptr && !(proc->state.mnstatus && !get_field(proc->state.mnstatus->read(), MNSTATUS_NMIE)) - && !proc->state.debug_mode + && (!proc->state.debug_mode || get_field(proc->state.dcsr->read(), DCSR_MPRVEN)) && get_field(proc->state.mstatus->read(), MSTATUS_MPRV); } @@ -509,8 +523,7 @@ private: bool check_triggers_fetch; bool check_triggers_load; bool check_triggers_store; - // The exception describing a matched trigger, or NULL. - triggers::matched_t *matched_trigger; + std::optional<triggers::matched_t> matched_trigger; friend class processor_t; }; diff --git a/riscv/ns16550.cc b/riscv/ns16550.cc index 2805fd8..15e0873 100644 --- a/riscv/ns16550.cc +++ b/riscv/ns16550.cc @@ -328,7 +328,7 @@ void ns16550_t::tick(reg_t UNUSED rtc_ticks) update_interrupt(); } -std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) +std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex @@ -348,7 +348,7 @@ std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string return s.str(); } -ns16550_t* ns16550_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& UNUSED sargs) +ns16550_t* ns16550_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& sargs UNUSED) { uint32_t ns16550_shift, ns16550_io_width, ns16550_int_id; if (fdt_parse_ns16550(fdt, base, diff --git a/riscv/platform.h b/riscv/platform.h index 7fffdc8..c8a5bf4 100644 --- a/riscv/platform.h +++ b/riscv/platform.h @@ -4,6 +4,8 @@ #define DEFAULT_KERNEL_BOOTARGS "console=ttyS0 earlycon" #define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_ISA "rv64imafdc_zicntr_zihpm" +#define DEFAULT_PRIV "MSU" #define CLINT_BASE 0x02000000 #define CLINT_SIZE 0x000c0000 #define PLIC_BASE 0x0c000000 diff --git a/riscv/plic.cc b/riscv/plic.cc index 78eb1d2..b6d204b 100644 --- a/riscv/plic.cc +++ b/riscv/plic.cc @@ -55,7 +55,7 @@ #define PENDING_BASE 0x1000 /* - * Each hart context has a vector of interupt enable bits associated with it. + * Each hart context has a vector of interrupt enable bits associated with it. * There's one bit for each interrupt source. */ #define ENABLE_BASE 0x2000 @@ -343,7 +343,8 @@ bool plic_t::load(reg_t addr, size_t len, uint8_t* bytes) return false; } - if (PRIORITY_BASE <= addr && addr < PENDING_BASE) { + static_assert(PRIORITY_BASE == 0); + if (/* PRIORITY_BASE <= addr && */ addr < PENDING_BASE) { ret = priority_read(addr, &val); } else if (PENDING_BASE <= addr && addr < ENABLE_BASE) { ret = pending_read(addr - PENDING_BASE, &val); @@ -384,7 +385,8 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) write_little_endian_reg(&val, addr, len, bytes); - if (PRIORITY_BASE <= addr && addr < ENABLE_BASE) { + static_assert(PRIORITY_BASE == 0); + if (/* PRIORITY_BASE <= addr && */ addr < ENABLE_BASE) { ret = priority_write(addr, val); } else if (ENABLE_BASE <= addr && addr < CONTEXT_BASE) { uint32_t cntx = (addr - ENABLE_BASE) / ENABLE_PER_HART; @@ -401,7 +403,7 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) return ret; } -std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) +std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex @@ -424,7 +426,7 @@ std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& return s.str(); } -plic_t* plic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& UNUSED sargs) +plic_t* plic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& sargs UNUSED) { uint32_t plic_ndev; if (fdt_parse_plic(fdt, base, &plic_ndev, "riscv,plic0") == 0 || diff --git a/riscv/processor.cc b/riscv/processor.cc index 9498b8f..6fe64ab 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -30,49 +30,51 @@ #undef STATE #define STATE state -processor_t::processor_t(const isa_parser_t *isa, const cfg_t *cfg, +processor_t::processor_t(const char* isa_str, const char* priv_str, + const cfg_t *cfg, simif_t* sim, uint32_t id, bool halt_on_reset, FILE* log_file, std::ostream& sout_) - : debug(false), halt_request(HR_NONE), isa(isa), cfg(cfg), sim(sim), id(id), xlen(0), +: debug(false), halt_request(HR_NONE), isa(isa_str, priv_str), cfg(cfg), + sim(sim), id(id), xlen(isa.get_max_xlen()), histogram_enabled(false), log_commits_enabled(false), log_file(log_file), sout_(sout_.rdbuf()), halt_on_reset(halt_on_reset), in_wfi(false), check_triggers_icount(false), - impl_table(256, false), extension_enable_table(isa->get_extension_table()), + impl_table(256, false), extension_enable_table(isa.get_extension_table()), last_pc(1), executions(1), TM(cfg->trigger_count) { VU.p = this; TM.proc = this; #ifndef HAVE_INT128 - if (isa->has_any_vector()) { + if (isa.has_any_vector()) { fprintf(stderr, "V extension is not supported on platforms without __int128 type\n"); abort(); } - if (isa->extension_enabled(EXT_ZACAS) && isa->get_max_xlen() == 64) { + if (isa.extension_enabled(EXT_ZACAS) && isa.get_max_xlen() == 64) { fprintf(stderr, "Zacas extension is not supported on 64-bit platforms without __int128 type\n"); abort(); } #endif - VU.VLEN = isa->get_vlen(); - VU.ELEN = isa->get_elen(); - VU.vlenb = isa->get_vlen() / 8; + VU.VLEN = isa.get_vlen(); + VU.ELEN = isa.get_elen(); + VU.vlenb = isa.get_vlen() / 8; VU.vstart_alu = 0; register_base_instructions(); - mmu = new mmu_t(sim, cfg->endianness, this); + mmu = new mmu_t(sim, cfg->endianness, this, cfg->cache_blocksz); - disassembler = new disassembler_t(isa); - for (auto e : isa->get_extensions()) + disassembler = new disassembler_t(&isa); + for (auto e : isa.get_extensions()) register_extension(find_extension(e.c_str())()); set_pmp_granularity(cfg->pmpgranularity); set_pmp_num(cfg->pmpregions); - if (isa->get_max_xlen() == 32) + if (isa.get_max_xlen() == 32) set_mmu_capability(IMPL_MMU_SV32); - else if (isa->get_max_xlen() == 64) + else if (isa.get_max_xlen() == 64) set_mmu_capability(IMPL_MMU_SV57); set_impl(IMPL_MMU_ASID, true); @@ -98,449 +100,21 @@ processor_t::~processor_t() delete disassembler; } -static void bad_option_string(const char *option, const char *value, - const char *msg) -{ - fprintf(stderr, "error: bad %s option '%s'. %s\n", option, value, msg); - abort(); -} - -static std::string get_string_token(std::string str, const char delimiter, size_t& pos) -{ - size_t _pos = pos; - while (pos < str.length() && str[pos] != delimiter) ++pos; - return str.substr(_pos, pos - _pos); -} - -static bool check_pow2(int val) -{ - return ((val & (val - 1))) == 0; -} - -static std::string strtolower(const char* str) -{ - std::string res; - for (const char *r = str; *r; r++) - res += std::tolower(*r); - return res; -} - -static int xlen_to_uxl(int xlen) -{ - if (xlen == 32) - return 1; - if (xlen == 64) - return 2; - abort(); -} - void state_t::reset(processor_t* const proc, reg_t max_isa) { pc = DEFAULT_RSTVEC; XPR.reset(); FPR.reset(); - // This assumes xlen is always max_xlen, which is true today (see - // mstatus_csr_t::unlogged_write()): - auto xlen = proc->get_isa().get_max_xlen(); - prv = prev_prv = PRV_M; v = prev_v = false; prv_changed = false; v_changed = false; - csrmap[CSR_MISA] = misa = std::make_shared<misa_csr_t>(proc, CSR_MISA, max_isa); - mstatus = std::make_shared<mstatus_csr_t>(proc, CSR_MSTATUS); - if (xlen == 32) { - csrmap[CSR_MSTATUS] = std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATUS, mstatus); - csrmap[CSR_MSTATUSH] = mstatush = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATUSH, mstatus); - } else { - csrmap[CSR_MSTATUS] = mstatus; - } - csrmap[CSR_MEPC] = mepc = std::make_shared<epc_csr_t>(proc, CSR_MEPC); - csrmap[CSR_MTVAL] = mtval = std::make_shared<basic_csr_t>(proc, CSR_MTVAL, 0); - csrmap[CSR_MSCRATCH] = std::make_shared<basic_csr_t>(proc, CSR_MSCRATCH, 0); - csrmap[CSR_MTVEC] = mtvec = std::make_shared<tvec_csr_t>(proc, CSR_MTVEC); - csrmap[CSR_MCAUSE] = mcause = std::make_shared<cause_csr_t>(proc, CSR_MCAUSE); - - auto smcntrpmf_enabled = proc->extension_enabled_const(EXT_SMCNTRPMF); - const reg_t mask = smcntrpmf_enabled ? MHPMEVENT_MINH | MHPMEVENT_SINH | - MHPMEVENT_UINH | MHPMEVENT_VSINH | MHPMEVENT_VUINH : 0; - auto minstretcfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MINSTRETCFG, mask, 0); - auto mcyclecfg = std::make_shared<smcntrpmf_csr_t>(proc, CSR_MCYCLECFG, mask, 0); - - minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET, minstretcfg); - mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE, mcyclecfg); - time = std::make_shared<time_counter_csr_t>(proc, CSR_TIME); - if (proc->extension_enabled_const(EXT_ZICNTR)) { - csrmap[CSR_INSTRET] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRET, minstret); - csrmap[CSR_CYCLE] = std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLE, mcycle); - csrmap[CSR_TIME] = time_proxy = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time); - } - if (xlen == 32) { - csr_t_p minstreth, mcycleh; - csrmap[CSR_MINSTRET] = std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRET, minstret); - csrmap[CSR_MINSTRETH] = minstreth = std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETH, minstret); - csrmap[CSR_MCYCLE] = std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLE, mcycle); - csrmap[CSR_MCYCLEH] = mcycleh = std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLEH, mcycle); - if (proc->extension_enabled_const(EXT_ZICNTR)) { - auto timeh = std::make_shared<rv32_high_csr_t>(proc, CSR_TIMEH, time); - csrmap[CSR_INSTRETH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRETH, minstreth); - csrmap[CSR_CYCLEH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLEH, mcycleh); - csrmap[CSR_TIMEH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIMEH, timeh); - } - } else { - csrmap[CSR_MINSTRET] = minstret; - csrmap[CSR_MCYCLE] = mcycle; - } - for (reg_t i = 3; i < N_HPMCOUNTERS + 3; ++i) { - const reg_t which_mevent = CSR_MHPMEVENT3 + i - 3; - const reg_t which_meventh = CSR_MHPMEVENT3H + i - 3; - const reg_t which_mcounter = CSR_MHPMCOUNTER3 + i - 3; - const reg_t which_mcounterh = CSR_MHPMCOUNTER3H + i - 3; - const reg_t which_counter = CSR_HPMCOUNTER3 + i - 3; - const reg_t which_counterh = CSR_HPMCOUNTER3H + i - 3; - mevent[i - 3] = std::make_shared<mevent_csr_t>(proc, which_mevent); - auto mcounter = std::make_shared<const_csr_t>(proc, which_mcounter, 0); - csrmap[which_mcounter] = mcounter; - - if (proc->extension_enabled_const(EXT_ZIHPM)) { - auto counter = std::make_shared<counter_proxy_csr_t>(proc, which_counter, mcounter); - csrmap[which_counter] = counter; - } - if (xlen == 32) { - csrmap[which_mevent] = std::make_shared<rv32_low_csr_t>(proc, which_mevent, mevent[i - 3]);; - auto mcounterh = std::make_shared<const_csr_t>(proc, which_mcounterh, 0); - csrmap[which_mcounterh] = mcounterh; - if (proc->extension_enabled_const(EXT_ZIHPM)) { - auto counterh = std::make_shared<counter_proxy_csr_t>(proc, which_counterh, mcounterh); - csrmap[which_counterh] = counterh; - } - if (proc->extension_enabled_const(EXT_SSCOFPMF)) { - auto meventh = std::make_shared<rv32_high_csr_t>(proc, which_meventh, mevent[i - 3]); - csrmap[which_meventh] = meventh; - } - } else { - csrmap[which_mevent] = mevent[i - 3]; - } - } - csrmap[CSR_MCOUNTINHIBIT] = std::make_shared<const_csr_t>(proc, CSR_MCOUNTINHIBIT, 0); - if (proc->extension_enabled_const(EXT_SSCOFPMF)) - csrmap[CSR_SCOUNTOVF] = std::make_shared<scountovf_csr_t>(proc, CSR_SCOUNTOVF); - csrmap[CSR_MIE] = mie = std::make_shared<mie_csr_t>(proc, CSR_MIE); - csrmap[CSR_MIP] = mip = std::make_shared<mip_csr_t>(proc, CSR_MIP); - auto sip_sie_accr = std::make_shared<generic_int_accessor_t>( - this, - ~MIP_HS_MASK, // read_mask - MIP_SSIP | MIP_LCOFIP, // ip_write_mask - ~MIP_HS_MASK, // ie_write_mask - generic_int_accessor_t::mask_mode_t::MIDELEG, - 0 // shiftamt - ); - - auto hip_hie_accr = std::make_shared<generic_int_accessor_t>( - this, - MIP_HS_MASK, // read_mask - MIP_VSSIP, // ip_write_mask - MIP_HS_MASK, // ie_write_mask - generic_int_accessor_t::mask_mode_t::MIDELEG, - 0 // shiftamt - ); - - auto vsip_vsie_accr = std::make_shared<generic_int_accessor_t>( - this, - MIP_VS_MASK, // read_mask - MIP_VSSIP, // ip_write_mask - MIP_VS_MASK, // ie_write_mask - generic_int_accessor_t::mask_mode_t::HIDELEG, - 1 // shiftamt - ); - - auto nonvirtual_sip = std::make_shared<mip_proxy_csr_t>(proc, CSR_SIP, sip_sie_accr); - auto vsip = std::make_shared<mip_proxy_csr_t>(proc, CSR_VSIP, vsip_vsie_accr); - csrmap[CSR_VSIP] = vsip; - csrmap[CSR_SIP] = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sip, vsip); - csrmap[CSR_HIP] = std::make_shared<mip_proxy_csr_t>(proc, CSR_HIP, hip_hie_accr); - csrmap[CSR_HVIP] = hvip = std::make_shared<hvip_csr_t>(proc, CSR_HVIP, 0); - - auto nonvirtual_sie = std::make_shared<mie_proxy_csr_t>(proc, CSR_SIE, sip_sie_accr); - auto vsie = std::make_shared<mie_proxy_csr_t>(proc, CSR_VSIE, vsip_vsie_accr); - csrmap[CSR_VSIE] = vsie; - csrmap[CSR_SIE] = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sie, vsie); - csrmap[CSR_HIE] = std::make_shared<mie_proxy_csr_t>(proc, CSR_HIE, hip_hie_accr); - - csrmap[CSR_MEDELEG] = medeleg = std::make_shared<medeleg_csr_t>(proc, CSR_MEDELEG); - csrmap[CSR_MIDELEG] = mideleg = std::make_shared<mideleg_csr_t>(proc, CSR_MIDELEG); - const reg_t counteren_mask = (proc->extension_enabled_const(EXT_ZICNTR) ? 0x7UL : 0x0) | (proc->extension_enabled_const(EXT_ZIHPM) ? 0xfffffff8ULL : 0x0); - mcounteren = std::make_shared<masked_csr_t>(proc, CSR_MCOUNTEREN, counteren_mask, 0); - if (proc->extension_enabled_const('U')) csrmap[CSR_MCOUNTEREN] = mcounteren; - csrmap[CSR_SCOUNTEREN] = scounteren = std::make_shared<masked_csr_t>(proc, CSR_SCOUNTEREN, counteren_mask, 0); - nonvirtual_sepc = std::make_shared<epc_csr_t>(proc, CSR_SEPC); - csrmap[CSR_VSEPC] = vsepc = std::make_shared<epc_csr_t>(proc, CSR_VSEPC); - csrmap[CSR_SEPC] = sepc = std::make_shared<virtualized_csr_t>(proc, nonvirtual_sepc, vsepc); - nonvirtual_stval = std::make_shared<basic_csr_t>(proc, CSR_STVAL, 0); - csrmap[CSR_VSTVAL] = vstval = std::make_shared<basic_csr_t>(proc, CSR_VSTVAL, 0); - csrmap[CSR_STVAL] = stval = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stval, vstval); - auto sscratch = std::make_shared<basic_csr_t>(proc, CSR_SSCRATCH, 0); - auto vsscratch = std::make_shared<basic_csr_t>(proc, CSR_VSSCRATCH, 0); - // Note: if max_isa does not include H, we don't really need this virtualized_csr_t at all (though it doesn't hurt): - csrmap[CSR_SSCRATCH] = std::make_shared<virtualized_csr_t>(proc, sscratch, vsscratch); - csrmap[CSR_VSSCRATCH] = vsscratch; - nonvirtual_stvec = std::make_shared<tvec_csr_t>(proc, CSR_STVEC); - csrmap[CSR_VSTVEC] = vstvec = std::make_shared<tvec_csr_t>(proc, CSR_VSTVEC); - csrmap[CSR_STVEC] = stvec = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stvec, vstvec); - auto nonvirtual_satp = std::make_shared<satp_csr_t>(proc, CSR_SATP); - csrmap[CSR_VSATP] = vsatp = std::make_shared<base_atp_csr_t>(proc, CSR_VSATP); - csrmap[CSR_SATP] = satp = std::make_shared<virtualized_satp_csr_t>(proc, nonvirtual_satp, vsatp); - nonvirtual_scause = std::make_shared<cause_csr_t>(proc, CSR_SCAUSE); - csrmap[CSR_VSCAUSE] = vscause = std::make_shared<cause_csr_t>(proc, CSR_VSCAUSE); - csrmap[CSR_SCAUSE] = scause = std::make_shared<virtualized_csr_t>(proc, nonvirtual_scause, vscause); - csrmap[CSR_MTVAL2] = mtval2 = std::make_shared<hypervisor_csr_t>(proc, CSR_MTVAL2); - csrmap[CSR_MTINST] = mtinst = std::make_shared<hypervisor_csr_t>(proc, CSR_MTINST); - const reg_t hstatus_init = set_field((reg_t)0, HSTATUS_VSXL, xlen_to_uxl(proc->get_const_xlen())); - const reg_t hstatus_mask = HSTATUS_VTSR | HSTATUS_VTW - | (proc->supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0) - | HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA; - csrmap[CSR_HSTATUS] = hstatus = std::make_shared<masked_csr_t>(proc, CSR_HSTATUS, hstatus_mask, hstatus_init); - csrmap[CSR_HGEIE] = std::make_shared<const_csr_t>(proc, CSR_HGEIE, 0); - csrmap[CSR_HGEIP] = std::make_shared<const_csr_t>(proc, CSR_HGEIP, 0); - csrmap[CSR_HIDELEG] = hideleg = std::make_shared<hideleg_csr_t>(proc, CSR_HIDELEG, mideleg); - const reg_t hedeleg_mask = - (1 << CAUSE_MISALIGNED_FETCH) | - (1 << CAUSE_FETCH_ACCESS) | - (1 << CAUSE_ILLEGAL_INSTRUCTION) | - (1 << CAUSE_BREAKPOINT) | - (1 << CAUSE_MISALIGNED_LOAD) | - (1 << CAUSE_LOAD_ACCESS) | - (1 << CAUSE_MISALIGNED_STORE) | - (1 << CAUSE_STORE_ACCESS) | - (1 << CAUSE_USER_ECALL) | - (1 << CAUSE_FETCH_PAGE_FAULT) | - (1 << CAUSE_LOAD_PAGE_FAULT) | - (1 << CAUSE_STORE_PAGE_FAULT) | - (1 << CAUSE_SOFTWARE_CHECK_FAULT); - csrmap[CSR_HEDELEG] = hedeleg = std::make_shared<masked_csr_t>(proc, CSR_HEDELEG, hedeleg_mask, 0); - csrmap[CSR_HCOUNTEREN] = hcounteren = std::make_shared<masked_csr_t>(proc, CSR_HCOUNTEREN, counteren_mask, 0); - htimedelta = std::make_shared<basic_csr_t>(proc, CSR_HTIMEDELTA, 0); - if (xlen == 32) { - csrmap[CSR_HTIMEDELTA] = std::make_shared<rv32_low_csr_t>(proc, CSR_HTIMEDELTA, htimedelta); - csrmap[CSR_HTIMEDELTAH] = std::make_shared<rv32_high_csr_t>(proc, CSR_HTIMEDELTAH, htimedelta); - } else { - csrmap[CSR_HTIMEDELTA] = htimedelta; - } - csrmap[CSR_HTVAL] = htval = std::make_shared<basic_csr_t>(proc, CSR_HTVAL, 0); - csrmap[CSR_HTINST] = htinst = std::make_shared<basic_csr_t>(proc, CSR_HTINST, 0); - csrmap[CSR_HGATP] = hgatp = std::make_shared<hgatp_csr_t>(proc, CSR_HGATP); - nonvirtual_sstatus = std::make_shared<sstatus_proxy_csr_t>(proc, CSR_SSTATUS, mstatus); - csrmap[CSR_VSSTATUS] = vsstatus = std::make_shared<vsstatus_csr_t>(proc, CSR_VSSTATUS); - csrmap[CSR_SSTATUS] = sstatus = std::make_shared<sstatus_csr_t>(proc, nonvirtual_sstatus, vsstatus); - - csrmap[CSR_DPC] = dpc = std::make_shared<dpc_csr_t>(proc, CSR_DPC); - csrmap[CSR_DSCRATCH0] = std::make_shared<debug_mode_csr_t>(proc, CSR_DSCRATCH0); - csrmap[CSR_DSCRATCH1] = std::make_shared<debug_mode_csr_t>(proc, CSR_DSCRATCH1); - csrmap[CSR_DCSR] = dcsr = std::make_shared<dcsr_csr_t>(proc, CSR_DCSR); - - csrmap[CSR_TSELECT] = tselect = std::make_shared<tselect_csr_t>(proc, CSR_TSELECT); - if (proc->get_cfg().trigger_count > 0) { - csrmap[CSR_TDATA1] = std::make_shared<tdata1_csr_t>(proc, CSR_TDATA1); - csrmap[CSR_TDATA2] = tdata2 = std::make_shared<tdata2_csr_t>(proc, CSR_TDATA2); - csrmap[CSR_TDATA3] = std::make_shared<tdata3_csr_t>(proc, CSR_TDATA3); - csrmap[CSR_TINFO] = std::make_shared<tinfo_csr_t>(proc, CSR_TINFO); - csrmap[CSR_TCONTROL] = tcontrol = std::make_shared<masked_csr_t>(proc, CSR_TCONTROL, CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE, 0); - } else { - csrmap[CSR_TDATA1] = std::make_shared<const_csr_t>(proc, CSR_TDATA1, 0); - csrmap[CSR_TDATA2] = tdata2 = std::make_shared<const_csr_t>(proc, CSR_TDATA2, 0); - csrmap[CSR_TDATA3] = std::make_shared<const_csr_t>(proc, CSR_TDATA3, 0); - csrmap[CSR_TINFO] = std::make_shared<const_csr_t>(proc, CSR_TINFO, 0); - csrmap[CSR_TCONTROL] = tcontrol = std::make_shared<const_csr_t>(proc, CSR_TCONTROL, 0); - } - unsigned scontext_length = (xlen == 32 ? 16 : 32); // debug spec suggests 16-bit for RV32 and 32-bit for RV64 - csrmap[CSR_SCONTEXT] = scontext = std::make_shared<masked_csr_t>(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0); - unsigned hcontext_length = (xlen == 32 ? 6 : 13) + (proc->extension_enabled('H') ? 1 : 0); // debug spec suggest 7-bit (6-bit) for RV32 and 14-bit (13-bit) for RV64 with (without) H extension - csrmap[CSR_HCONTEXT] = std::make_shared<masked_csr_t>(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); - csrmap[CSR_MCONTEXT] = mcontext = std::make_shared<proxy_csr_t>(proc, CSR_MCONTEXT, csrmap[CSR_HCONTEXT]); + serialized = false; debug_mode = false; single_step = STEP_NONE; - csrmap[CSR_MSECCFG] = mseccfg = std::make_shared<mseccfg_csr_t>(proc, CSR_MSECCFG); - - for (int i = 0; i < max_pmp; ++i) { - csrmap[CSR_PMPADDR0 + i] = pmpaddr[i] = std::make_shared<pmpaddr_csr_t>(proc, CSR_PMPADDR0 + i); - } - for (int i = 0; i < max_pmp; i += xlen / 8) { - reg_t addr = CSR_PMPCFG0 + i / 4; - csrmap[addr] = std::make_shared<pmpcfg_csr_t>(proc, addr); - } - - csrmap[CSR_FFLAGS] = fflags = std::make_shared<float_csr_t>(proc, CSR_FFLAGS, FSR_AEXC >> FSR_AEXC_SHIFT, 0); - csrmap[CSR_FRM] = frm = std::make_shared<float_csr_t>(proc, CSR_FRM, FSR_RD >> FSR_RD_SHIFT, 0); - assert(FSR_AEXC_SHIFT == 0); // composite_csr_t assumes fflags begins at bit 0 - csrmap[CSR_FCSR] = std::make_shared<composite_csr_t>(proc, CSR_FCSR, frm, fflags, FSR_RD_SHIFT); - - csrmap[CSR_SEED] = std::make_shared<seed_csr_t>(proc, CSR_SEED); - - csrmap[CSR_MARCHID] = std::make_shared<const_csr_t>(proc, CSR_MARCHID, 5); - csrmap[CSR_MIMPID] = std::make_shared<const_csr_t>(proc, CSR_MIMPID, 0); - csrmap[CSR_MVENDORID] = std::make_shared<const_csr_t>(proc, CSR_MVENDORID, 0); - csrmap[CSR_MHARTID] = std::make_shared<const_csr_t>(proc, CSR_MHARTID, proc->get_id()); - csrmap[CSR_MCONFIGPTR] = std::make_shared<const_csr_t>(proc, CSR_MCONFIGPTR, 0); - if (proc->extension_enabled_const('U')) { - const reg_t menvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? MENVCFG_CBCFE | MENVCFG_CBIE : 0) | - (proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE : 0) | - (proc->extension_enabled(EXT_SVADU) ? MENVCFG_ADUE: 0) | - (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) | - (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0) | - (proc->extension_enabled(EXT_ZICFISS) ? MENVCFG_SSE : 0); - const reg_t menvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0); - menvcfg = std::make_shared<envcfg_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, menvcfg_init); - if (xlen == 32) { - csrmap[CSR_MENVCFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_MENVCFG, menvcfg); - csrmap[CSR_MENVCFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MENVCFGH, menvcfg); - } else { - csrmap[CSR_MENVCFG] = menvcfg; - } - const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE : 0) | - (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0) | - (proc->extension_enabled(EXT_ZICFISS) ? SENVCFG_SSE : 0); - csrmap[CSR_SENVCFG] = senvcfg = std::make_shared<senvcfg_csr_t>(proc, CSR_SENVCFG, senvcfg_mask, 0); - const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE : 0) | - (proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE : 0) | - (proc->extension_enabled(EXT_SVADU) ? HENVCFG_ADUE: 0) | - (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) | - (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? HENVCFG_LPE : 0) | - (proc->extension_enabled(EXT_ZICFISS) ? HENVCFG_SSE : 0); - const reg_t henvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0); - henvcfg = std::make_shared<henvcfg_csr_t>(proc, CSR_HENVCFG, henvcfg_mask, henvcfg_init, menvcfg); - if (xlen == 32) { - csrmap[CSR_HENVCFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_HENVCFG, henvcfg); - csrmap[CSR_HENVCFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_HENVCFGH, henvcfg); - } else { - csrmap[CSR_HENVCFG] = henvcfg; - } - } - if (proc->extension_enabled_const(EXT_SMSTATEEN)) { - const reg_t sstateen0_mask = (proc->extension_enabled(EXT_ZFINX) ? SSTATEEN0_FCSR : 0) | - (proc->extension_enabled(EXT_ZCMT) ? SSTATEEN0_JVT : 0) | - SSTATEEN0_CS; - const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN; - const reg_t mstateen0_mask = hstateen0_mask | (proc->extension_enabled(EXT_SSQOSID) ? MSTATEEN0_PRIV114 : 0); - for (int i = 0; i < 4; i++) { - const reg_t mstateen_mask = i == 0 ? mstateen0_mask : MSTATEEN_HSTATEEN; - mstateen[i] = std::make_shared<masked_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0); - if (xlen == 32) { - csrmap[CSR_MSTATEEN0 + i] = std::make_shared<rv32_low_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen[i]); - csrmap[CSR_MSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_MSTATEEN0H + i, mstateen[i]); - } else { - csrmap[CSR_MSTATEEN0 + i] = mstateen[i]; - } - - const reg_t hstateen_mask = i == 0 ? hstateen0_mask : HSTATEEN_SSTATEEN; - hstateen[i] = std::make_shared<hstateen_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen_mask, 0, i); - if (xlen == 32) { - csrmap[CSR_HSTATEEN0 + i] = std::make_shared<rv32_low_csr_t>(proc, CSR_HSTATEEN0 + i, hstateen[i]); - csrmap[CSR_HSTATEEN0H + i] = std::make_shared<rv32_high_csr_t>(proc, CSR_HSTATEEN0H + i, hstateen[i]); - } else { - csrmap[CSR_HSTATEEN0 + i] = hstateen[i]; - } - - const reg_t sstateen_mask = i == 0 ? sstateen0_mask : 0; - csrmap[CSR_SSTATEEN0 + i] = sstateen[i] = std::make_shared<sstateen_csr_t>(proc, CSR_SSTATEEN0 + i, sstateen_mask, 0, i); - } - } - - if (proc->extension_enabled_const(EXT_SMRNMI)) { - csrmap[CSR_MNSCRATCH] = std::make_shared<basic_csr_t>(proc, CSR_MNSCRATCH, 0); - csrmap[CSR_MNEPC] = mnepc = std::make_shared<epc_csr_t>(proc, CSR_MNEPC); - csrmap[CSR_MNCAUSE] = std::make_shared<const_csr_t>(proc, CSR_MNCAUSE, (reg_t)1 << (xlen - 1)); - csrmap[CSR_MNSTATUS] = mnstatus = std::make_shared<mnstatus_csr_t>(proc, CSR_MNSTATUS); - } - - if (proc->extension_enabled_const(EXT_SSTC)) { - stimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_STIMECMP, MIP_STIP); - vstimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_VSTIMECMP, MIP_VSTIP); - auto virtualized_stimecmp = std::make_shared<virtualized_stimecmp_csr_t>(proc, stimecmp, vstimecmp); - if (xlen == 32) { - csrmap[CSR_STIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_STIMECMP, virtualized_stimecmp); - csrmap[CSR_STIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_STIMECMPH, virtualized_stimecmp); - csrmap[CSR_VSTIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_VSTIMECMP, vstimecmp); - csrmap[CSR_VSTIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_VSTIMECMPH, vstimecmp); - } else { - csrmap[CSR_STIMECMP] = virtualized_stimecmp; - csrmap[CSR_VSTIMECMP] = vstimecmp; - } - } - - if (proc->extension_enabled(EXT_ZCMT)) - csrmap[CSR_JVT] = jvt = std::make_shared<jvt_csr_t>(proc, CSR_JVT, 0); - - if (proc->extension_enabled(EXT_ZICFISS)) { - reg_t ssp_mask = -reg_t(xlen / 8); - csrmap[CSR_SSP] = ssp = std::make_shared<ssp_csr_t>(proc, CSR_SSP, ssp_mask, 0); - } - - - // Smcsrind / Sscsrind - sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg[6]; - sscsrind_reg_csr_t::sscsrind_reg_csr_t_p sireg[6]; - sscsrind_reg_csr_t::sscsrind_reg_csr_t_p vsireg[6]; - - if (proc->extension_enabled_const(EXT_SMCSRIND)) { - csr_t_p miselect = std::make_shared<basic_csr_t>(proc, CSR_MISELECT, 0); - csrmap[CSR_MISELECT] = miselect; - - const reg_t mireg_csrs[] = { CSR_MIREG, CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; - auto i = 0; - for (auto csr : mireg_csrs) { - csrmap[csr] = mireg[i] = std::make_shared<sscsrind_reg_csr_t>(proc, csr, miselect); - i++; - } - } - - if (proc->extension_enabled_const(EXT_SSCSRIND)) { - csr_t_p vsiselect = std::make_shared<basic_csr_t>(proc, CSR_VSISELECT, 0); - csrmap[CSR_VSISELECT] = vsiselect; - csr_t_p siselect = std::make_shared<basic_csr_t>(proc, CSR_SISELECT, 0); - csrmap[CSR_SISELECT] = std::make_shared<virtualized_csr_t>(proc, siselect, vsiselect); - - const reg_t vsireg_csrs[] = { CSR_VSIREG, CSR_VSIREG2, CSR_VSIREG3, CSR_VSIREG4, CSR_VSIREG5, CSR_VSIREG6 }; - auto i = 0; - for (auto csr : vsireg_csrs) { - csrmap[csr] = vsireg[i] = std::make_shared<sscsrind_reg_csr_t>(proc, csr, vsiselect); - i++; - } - - const reg_t sireg_csrs[] = { CSR_SIREG, CSR_SIREG2, CSR_SIREG3, CSR_SIREG4, CSR_SIREG5, CSR_SIREG6 }; - i = 0; - for (auto csr : sireg_csrs) { - sireg[i] = std::make_shared<sscsrind_reg_csr_t>(proc, csr, siselect); - csrmap[csr] = std::make_shared<virtualized_indirect_csr_t>(proc, sireg[i], vsireg[i]); - i++; - } - } - - if (smcntrpmf_enabled) { - if (xlen == 32) { - csrmap[CSR_MCYCLECFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLECFG, mcyclecfg); - csrmap[CSR_MCYCLECFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLECFGH, mcyclecfg); - csrmap[CSR_MINSTRETCFG] = std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRETCFG, minstretcfg); - csrmap[CSR_MINSTRETCFGH] = std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETCFGH, minstretcfg); - } else { - csrmap[CSR_MCYCLECFG] = mcyclecfg; - csrmap[CSR_MINSTRETCFG] = minstretcfg; - } - } - - if (proc->extension_enabled_const(EXT_SSQOSID)) { - const reg_t srmcfg_mask = SRMCFG_MCID | SRMCFG_RCID; - srmcfg = std::make_shared<srmcfg_csr_t>(proc, CSR_SRMCFG, srmcfg_mask, 0); - csrmap[CSR_SRMCFG] = srmcfg; - } - - serialized = false; - log_reg_write.clear(); log_mem_read.clear(); log_mem_write.clear(); @@ -549,6 +123,10 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) last_inst_flen = 0; elp = elp_t::NO_LP_EXPECTED; + + critical_error = false; + + csr_init(proc, max_isa); } void processor_t::set_debug(bool value) @@ -556,7 +134,7 @@ void processor_t::set_debug(bool value) debug = value; for (auto e : custom_extensions) - e.second->set_debug(value); + e.second->set_debug(value, *this); } void processor_t::set_histogram(bool value) @@ -567,15 +145,15 @@ void processor_t::set_histogram(bool value) void processor_t::enable_log_commits() { log_commits_enabled = true; + mmu->flush_tlb(); // the TLB caches this setting } void processor_t::reset() { - xlen = isa->get_max_xlen(); - state.reset(this, isa->get_max_isa()); - state.dcsr->halt = halt_on_reset; - halt_on_reset = false; - VU.reset(); + xlen = isa.get_max_xlen(); + state.reset(this, isa.get_max_isa()); + if (any_vector_extensions()) + VU.reset(); in_wfi = false; if (n_pmp > 0) { @@ -585,8 +163,11 @@ void processor_t::reset() put_csr(CSR_PMPCFG0, PMP_R | PMP_W | PMP_X | PMP_NAPOT); } - for (auto e : custom_extensions) // reset any extensions - e.second->reset(); + for (auto e : custom_extensions) { // reset any extensions + for (auto &csr: e.second->get_csrs(*this)) + state.add_csr(csr->address, csr); + e.second->reset(*this); + } if (sim) sim->proc_reset(id); @@ -643,10 +224,10 @@ void processor_t::set_mmu_capability(int cap) break; case IMPL_MMU_SV57: set_impl(IMPL_MMU_SV57, true); - // Fall through + [[fallthrough]]; case IMPL_MMU_SV48: set_impl(IMPL_MMU_SV48, true); - // Fall through + [[fallthrough]]; case IMPL_MMU_SV39: set_impl(IMPL_MMU_SV39, true); set_impl(IMPL_MMU, true); @@ -661,10 +242,79 @@ void processor_t::set_mmu_capability(int cap) } } +reg_t processor_t::select_an_interrupt_with_default_priority(reg_t enabled_interrupts) const +{ + // nonstandard interrupts have highest priority + if (enabled_interrupts >> (IRQ_LCOF + 1)) + enabled_interrupts = enabled_interrupts >> (IRQ_LCOF + 1) << (IRQ_LCOF + 1); + // standard interrupt priority is MEI, MSI, MTI, SEI, SSI, STI + else if (enabled_interrupts & MIP_MEIP) + enabled_interrupts = MIP_MEIP; + else if (enabled_interrupts & MIP_MSIP) + enabled_interrupts = MIP_MSIP; + else if (enabled_interrupts & MIP_MTIP) + enabled_interrupts = MIP_MTIP; + else if (enabled_interrupts & MIP_SEIP) + enabled_interrupts = MIP_SEIP; + else if (enabled_interrupts & MIP_SSIP) + enabled_interrupts = MIP_SSIP; + else if (enabled_interrupts & MIP_STIP) + enabled_interrupts = MIP_STIP; + else if (enabled_interrupts & MIP_LCOFIP) + enabled_interrupts = MIP_LCOFIP; + else if (enabled_interrupts & MIP_VSEIP) + enabled_interrupts = MIP_VSEIP; + else if (enabled_interrupts & MIP_VSSIP) + enabled_interrupts = MIP_VSSIP; + else if (enabled_interrupts & MIP_VSTIP) + enabled_interrupts = MIP_VSTIP; + + return enabled_interrupts; +} + +bool processor_t::is_handled_in_vs() +{ + reg_t pending_interrupts = state.mip->read() & state.mie->read(); + + const reg_t s_pending_interrupts = state.nonvirtual_sip->read() & state.nonvirtual_sie->read(); + const reg_t vstopi = state.vstopi->read(); + const reg_t vs_pending_interrupt = vstopi ? (reg_t(1) << get_field(vstopi, MTOPI_IID)) : 0; // SSIP -> VSSIP, etc + + // M-ints have higher priority over HS-ints and VS-ints + const reg_t mie = get_field(state.mstatus->read(), MSTATUS_MIE); + const reg_t m_enabled = state.prv < PRV_M || (state.prv == PRV_M && mie); + reg_t enabled_interrupts = pending_interrupts & ~state.mideleg->read() & -m_enabled; + if (enabled_interrupts == 0) { + // HS-ints have higher priority over VS-ints + const reg_t deleg_to_hs = state.mideleg->read() & ~state.hideleg->read(); + const reg_t sie = get_field(state.sstatus->read(), MSTATUS_SIE); + const reg_t hs_enabled = state.v || state.prv < PRV_S || (state.prv == PRV_S && sie); + enabled_interrupts = ((pending_interrupts & deleg_to_hs) | (s_pending_interrupts & ~state.hideleg->read())) & -hs_enabled; + if (state.v && enabled_interrupts == 0) { + // VS-ints have least priority and can only be taken with virt enabled + const reg_t vs_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie); + enabled_interrupts = vs_pending_interrupt & -vs_enabled; + if (enabled_interrupts) + return true; + } + } + return false; +} + void processor_t::take_interrupt(reg_t pending_interrupts) { + reg_t s_pending_interrupts = 0; + reg_t vstopi = 0; + reg_t vs_pending_interrupt = 0; + + if (extension_enable_table[EXT_SSAIA]) { + s_pending_interrupts = state.nonvirtual_sip->read() & state.nonvirtual_sie->read(); + vstopi = state.vstopi->read(); + vs_pending_interrupt = vstopi ? (reg_t(1) << get_field(vstopi, MTOPI_IID)) : 0; + } + // Do nothing if no pending interrupts - if (!pending_interrupts) { + if (!pending_interrupts && !s_pending_interrupts && !vs_pending_interrupt) { return; } @@ -680,46 +330,20 @@ void processor_t::take_interrupt(reg_t pending_interrupts) const reg_t deleg_to_hs = state.mideleg->read() & ~state.hideleg->read(); const reg_t sie = get_field(state.sstatus->read(), MSTATUS_SIE); const reg_t hs_enabled = state.v || state.prv < PRV_S || (state.prv == PRV_S && sie); - enabled_interrupts = pending_interrupts & deleg_to_hs & -hs_enabled; + enabled_interrupts = ((pending_interrupts & deleg_to_hs) | (s_pending_interrupts & ~state.hideleg->read())) & -hs_enabled; if (state.v && enabled_interrupts == 0) { // VS-ints have least priority and can only be taken with virt enabled - const reg_t deleg_to_vs = state.hideleg->read(); const reg_t vs_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie); - enabled_interrupts = pending_interrupts & deleg_to_vs & -vs_enabled; + enabled_interrupts = vs_pending_interrupt & -vs_enabled; } } const bool nmie = !(state.mnstatus && !get_field(state.mnstatus->read(), MNSTATUS_NMIE)); if (!state.debug_mode && nmie && enabled_interrupts) { - // nonstandard interrupts have highest priority - if (enabled_interrupts >> (IRQ_M_EXT + 1)) - enabled_interrupts = enabled_interrupts >> (IRQ_M_EXT + 1) << (IRQ_M_EXT + 1); - // standard interrupt priority is MEI, MSI, MTI, SEI, SSI, STI - else if (enabled_interrupts & MIP_MEIP) - enabled_interrupts = MIP_MEIP; - else if (enabled_interrupts & MIP_MSIP) - enabled_interrupts = MIP_MSIP; - else if (enabled_interrupts & MIP_MTIP) - enabled_interrupts = MIP_MTIP; - else if (enabled_interrupts & MIP_SEIP) - enabled_interrupts = MIP_SEIP; - else if (enabled_interrupts & MIP_SSIP) - enabled_interrupts = MIP_SSIP; - else if (enabled_interrupts & MIP_STIP) - enabled_interrupts = MIP_STIP; - else if (enabled_interrupts & MIP_LCOFIP) - enabled_interrupts = MIP_LCOFIP; - else if (enabled_interrupts & MIP_VSEIP) - enabled_interrupts = MIP_VSEIP; - else if (enabled_interrupts & MIP_VSSIP) - enabled_interrupts = MIP_VSSIP; - else if (enabled_interrupts & MIP_VSTIP) - enabled_interrupts = MIP_VSTIP; - else - abort(); + reg_t selected_interrupt = select_an_interrupt_with_default_priority(enabled_interrupts); if (check_triggers_icount) TM.detect_icount_match(); - throw trap_t(((reg_t)1 << (isa->get_max_xlen() - 1)) | ctz(enabled_interrupts)); + throw trap_t(((reg_t)1 << (isa.get_max_xlen() - 1)) | ctz(selected_interrupt)); } } @@ -747,7 +371,7 @@ void processor_t::set_privilege(reg_t prv, bool virt) state.v_changed = state.v != state.prev_v; } -const char* processor_t::get_privilege_string() +const char* processor_t::get_privilege_string() const { if (state.debug_mode) return "D"; @@ -767,11 +391,11 @@ const char* processor_t::get_privilege_string() abort(); } -void processor_t::enter_debug_mode(uint8_t cause) +void processor_t::enter_debug_mode(uint8_t cause, uint8_t extcause) { const bool has_zicfilp = extension_enabled(EXT_ZICFILP); state.debug_mode = true; - state.dcsr->update_fields(cause, state.prv, state.v, state.elp); + state.dcsr->update_fields(cause, extcause, state.prv, state.v, state.elp); state.elp = elp_t::NO_LP_EXPECTED; set_privilege(PRV_M, false); state.dpc->write(state.pc); @@ -791,7 +415,7 @@ void processor_t::debug_output_log(std::stringstream *s) void processor_t::take_trap(trap_t& t, reg_t epc) { - unsigned max_xlen = isa->get_max_xlen(); + unsigned max_xlen = isa.get_max_xlen(); if (debug) { std::stringstream s; // first put everything in a string, later send it to output @@ -820,17 +444,30 @@ void processor_t::take_trap(trap_t& t, reg_t epc) bool curr_virt = state.v; const reg_t interrupt_bit = (reg_t)1 << (max_xlen - 1); bool interrupt = (bit & interrupt_bit) != 0; + bool supv_double_trap = false; if (interrupt) { vsdeleg = (curr_virt && state.prv <= PRV_S) ? state.hideleg->read() : 0; - hsdeleg = (state.prv <= PRV_S) ? state.mideleg->read() : 0; + vsdeleg >>= 1; + hsdeleg = (state.prv <= PRV_S) ? (state.mideleg->read() | state.nonvirtual_sip->read()) : 0; bit &= ~((reg_t)1 << (max_xlen - 1)); } else { vsdeleg = (curr_virt && state.prv <= PRV_S) ? (state.medeleg->read() & state.hedeleg->read()) : 0; hsdeleg = (state.prv <= PRV_S) ? state.medeleg->read() : 0; } - if (state.prv <= PRV_S && bit < max_xlen && ((vsdeleg >> bit) & 1)) { + // An unexpected trap - a trap when SDT is 1 - traps to M-mode + if ((state.prv <= PRV_S && bit < max_xlen) && + (((vsdeleg >> bit) & 1) || ((hsdeleg >> bit) & 1))) { + // Trap is handled in VS-mode or HS-mode. Read the sstatus of the + // mode that will handle the trap based on the delegation control + reg_t s = (((vsdeleg >> bit) & 1)) ? state.sstatus->read() : + state.nonvirtual_sstatus->read(); + supv_double_trap = get_field(s, MSTATUS_SDT); + if (supv_double_trap) + vsdeleg = hsdeleg = 0; + } + if ((state.prv <= PRV_S && bit < max_xlen && ((vsdeleg >> bit) & 1)) || (state.v && interrupt && is_handled_in_vs())) { // Handle the trap in VS-mode - const reg_t adjusted_cause = interrupt ? bit - 1 : bit; // VSSIP -> SSIP, etc + const reg_t adjusted_cause = bit; reg_t vector = (state.vstvec->read() & 1) && interrupt ? 4 * adjusted_cause : 0; state.pc = (state.vstvec->read() & ~(reg_t)1) + vector; state.vscause->write(adjusted_cause | (interrupt ? interrupt_bit : 0)); @@ -842,6 +479,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc) s = set_field(s, MSTATUS_SPP, state.prv); s = set_field(s, MSTATUS_SIE, 0); s = set_field(s, MSTATUS_SPELP, state.elp); + if ((state.menvcfg->read() & MENVCFG_DTE) && (state.henvcfg->read() & HENVCFG_DTE)) + s = set_field(s, MSTATUS_SDT, 1); state.elp = elp_t::NO_LP_EXPECTED; state.sstatus->write(s); set_privilege(PRV_S, true); @@ -860,6 +499,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc) s = set_field(s, MSTATUS_SPP, state.prv); s = set_field(s, MSTATUS_SIE, 0); s = set_field(s, MSTATUS_SPELP, state.elp); + if (state.menvcfg->read() & MENVCFG_DTE) + s = set_field(s, MSTATUS_SDT, 1); state.elp = elp_t::NO_LP_EXPECTED; state.nonvirtual_sstatus->write(s); if (extension_enabled('H')) { @@ -875,18 +516,30 @@ void processor_t::take_trap(trap_t& t, reg_t epc) // Handle the trap in M-mode const reg_t vector = (state.mtvec->read() & 1) && interrupt ? 4 * bit : 0; const reg_t trap_handler_address = (state.mtvec->read() & ~(reg_t)1) + vector; - // RNMI exception vector is implementation-defined. Since we don't model // RNMI sources, the feature isn't very useful, so pick an invalid address. + // RNMI exception vector is implementation-defined. Since we don't model const reg_t rnmi_trap_handler_address = 0; const bool nmie = !(state.mnstatus && !get_field(state.mnstatus->read(), MNSTATUS_NMIE)); + + reg_t s = state.mstatus->read(); + if ( extension_enabled(EXT_SMDBLTRP)) { + if (get_field(s, MSTATUS_MDT) || !nmie) { + // Critical error - Double trap in M-mode or trap when nmie is 0 + // RNMI is not modeled else double trap in M-mode would trap to + // RNMI handler instead of leading to a critical error + state.critical_error = 1; + return; + } + s = set_field(s, MSTATUS_MDT, 1); + } + state.pc = !nmie ? rnmi_trap_handler_address : trap_handler_address; state.mepc->write(epc); - state.mcause->write(t.cause()); + state.mcause->write(supv_double_trap ? CAUSE_DOUBLE_TRAP : t.cause()); state.mtval->write(t.get_tval()); - state.mtval2->write(t.get_tval2()); + state.mtval2->write(supv_double_trap ? t.cause() : t.get_tval2()); state.mtinst->write(t.get_tinst()); - reg_t s = state.mstatus->read(); s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE)); s = set_field(s, MSTATUS_MPP, state.prv); s = set_field(s, MSTATUS_MIE, 0); @@ -896,7 +549,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc) state.elp = elp_t::NO_LP_EXPECTED; state.mstatus->write(s); if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change - state.tcontrol->write((state.tcontrol->read() & CSR_TCONTROL_MTE) ? CSR_TCONTROL_MPTE : 0); + if (state.tcontrol) state.tcontrol->write((state.tcontrol->read() & CSR_TCONTROL_MTE) ? CSR_TCONTROL_MPTE : 0); set_privilege(PRV_M, false); } } @@ -912,7 +565,7 @@ void processor_t::take_trigger_action(triggers::action_t action, reg_t breakpoin switch (action) { case triggers::ACTION_DEBUG_MODE: - enter_debug_mode(DCSR_CAUSE_HWBP); + enter_debug_mode(DCSR_CAUSE_HWBP, 0); break; case triggers::ACTION_DEBUG_EXCEPTION: { trap_breakpoint trap(virt, breakpoint_tval); @@ -956,7 +609,7 @@ void processor_t::disasm(insn_t insn) << ": Executed " << executions << " times" << std::endl; } - unsigned max_xlen = isa->get_max_xlen(); + unsigned max_xlen = isa.get_max_xlen(); s << "core " << std::dec << std::setfill(' ') << std::setw(3) << id << std::hex << ": 0x" << std::setfill('0') << std::setw(max_xlen / 4) @@ -975,7 +628,7 @@ void processor_t::disasm(insn_t insn) int processor_t::paddr_bits() { - unsigned max_xlen = isa->get_max_xlen(); + unsigned max_xlen = isa.get_max_xlen(); assert(xlen == max_xlen); return max_xlen == 64 ? 50 : 34; } @@ -1063,18 +716,17 @@ void processor_t::build_opcode_map() } void processor_t::register_extension(extension_t *x) { - for (auto insn : x->get_instructions()) + for (auto insn : x->get_instructions(*this)) register_custom_insn(insn); build_opcode_map(); - for (auto disasm_insn : x->get_disasms()) + for (auto disasm_insn : x->get_disasms(this)) disassembler->add_insn(disasm_insn); if (!custom_extensions.insert(std::make_pair(x->name(), x)).second) { fprintf(stderr, "extensions must have unique names (got two named \"%s\"!)\n", x->name()); abort(); } - x->set_processor(this); } void processor_t::register_base_instructions() @@ -1099,21 +751,27 @@ void processor_t::register_base_instructions() #include "insn_list.h" #undef DEFINE_INSN + #define DEFINE_INSN_UNCOND(name) { \ + insn_desc_t insn = { \ + name##_match, \ + name##_mask, \ + fast_rv32i_##name, \ + fast_rv64i_##name, \ + fast_rv32e_##name, \ + fast_rv64e_##name, \ + logged_rv32i_##name, \ + logged_rv64i_##name, \ + logged_rv32e_##name, \ + logged_rv64e_##name \ + }; \ + register_base_insn(insn); \ + } + // add overlapping instructions first, in order #define DECLARE_OVERLAP_INSN(name, ext) \ name##_overlapping = true; \ - if (isa->extension_enabled(ext)) \ - register_base_insn((insn_desc_t) { \ - name##_match, \ - name##_mask, \ - fast_rv32i_##name, \ - fast_rv64i_##name, \ - fast_rv32e_##name, \ - fast_rv64e_##name, \ - logged_rv32i_##name, \ - logged_rv64i_##name, \ - logged_rv32e_##name, \ - logged_rv64e_##name}); + if (isa.extension_enabled(ext)) \ + DEFINE_INSN_UNCOND(name); #include "overlap_list.h" #undef DECLARE_OVERLAP_INSN @@ -1122,19 +780,10 @@ void processor_t::register_base_instructions() // appear earlier to improve search time on opcode_cache misses. #define DEFINE_INSN(name) \ if (!name##_overlapping) \ - register_base_insn((insn_desc_t) { \ - name##_match, \ - name##_mask, \ - fast_rv32i_##name, \ - fast_rv64i_##name, \ - fast_rv32e_##name, \ - fast_rv64e_##name, \ - logged_rv32i_##name, \ - logged_rv64i_##name, \ - logged_rv32e_##name, \ - logged_rv64e_##name}); + DEFINE_INSN_UNCOND(name); #include "insn_list.h" #undef DEFINE_INSN + #undef DEFINE_INSN_UNCOND // terminate instruction list with a catch-all register_base_insn(insn_desc_t::illegal_instruction); @@ -1173,6 +822,11 @@ bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } +reg_t processor_t::size() +{ + return PGSIZE; +} + void processor_t::trigger_updated(const std::vector<triggers::trigger_t *> &triggers) { mmu->flush_tlb(); diff --git a/riscv/processor.h b/riscv/processor.h index 14b828c..a6e9eeb 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -18,6 +18,7 @@ #include "../fesvr/memif.h" #include "vector_unit.h" +#define FIRST_HPMCOUNTER 3 #define N_HPMCOUNTERS 29 class processor_t; @@ -61,7 +62,7 @@ struct insn_desc_t }; // regnum, data -typedef std::unordered_map<reg_t, freg_t> commit_log_reg_t; +typedef std::map<reg_t, freg_t> commit_log_reg_t; // addr, value, size typedef std::vector<std::tuple<reg_t, uint64_t, uint8_t>> commit_log_mem_t; @@ -69,7 +70,9 @@ typedef std::vector<std::tuple<reg_t, uint64_t, uint8_t>> commit_log_mem_t; // architectural state of a RISC-V hart struct state_t { + void add_ireg_proxy(processor_t* const proc, sscsrind_reg_csr_t::sscsrind_reg_csr_t_p ireg); void reset(processor_t* const proc, reg_t max_isa); + void add_csr(reg_t addr, const csr_t_p& csr); reg_t pc; regfile_t<reg_t, NXPR, true> XPR; @@ -94,9 +97,12 @@ struct state_t wide_counter_csr_t_p mcycle; mie_csr_t_p mie; mip_csr_t_p mip; + csr_t_p nonvirtual_sip; + csr_t_p nonvirtual_sie; csr_t_p medeleg; csr_t_p mideleg; csr_t_p mcounteren; + csr_t_p mcountinhibit; csr_t_p mevent[N_HPMCOUNTERS]; csr_t_p mnstatus; csr_t_p mnepc; @@ -106,6 +112,7 @@ struct state_t csr_t_p stvec; virtualized_csr_t_p satp; csr_t_p scause; + csr_t_p scountinhibit; // When taking a trap into HS-mode, we must access the nonvirtualized HS-mode CSRs directly: csr_t_p nonvirtual_stvec; @@ -167,10 +174,13 @@ struct state_t csr_t_p stimecmp; csr_t_p vstimecmp; - csr_t_p srmcfg; - csr_t_p ssp; + csr_t_p mvien; + mvip_csr_t_p mvip; + csr_t_p hvictl; + csr_t_p vstopi; + bool serialized; // whether timer CSRs are in a well-defined state // When true, execute a single instruction and then enter debug mode. This @@ -189,6 +199,11 @@ struct state_t int last_inst_flen; elp_t elp; + + bool critical_error; + + private: + void csr_init(processor_t* const proc, reg_t max_isa); }; class opcode_cache_entry_t { @@ -236,13 +251,14 @@ class opcode_cache_entry_t { class processor_t : public abstract_device_t { public: - processor_t(const isa_parser_t *isa, const cfg_t* cfg, + processor_t(const char* isa_str, const char* priv_str, + const cfg_t* cfg, simif_t* sim, uint32_t id, bool halt_on_reset, FILE *log_file, std::ostream& sout_); // because of command line option --log and -s we need both ~processor_t(); - const isa_parser_t &get_isa() { return *isa; } - const cfg_t &get_cfg() { return *cfg; } + const isa_parser_t &get_isa() const & { return isa; } + const cfg_t &get_cfg() const & { return *cfg; } void set_debug(bool value); void set_histogram(bool value); @@ -303,7 +319,7 @@ public: void set_extension_enable(unsigned char ext, bool enable) { assert(!extension_assumed_const[ext]); extension_dynamic[ext] = true; - extension_enable_table[ext] = enable && isa->extension_enabled(ext); + extension_enable_table[ext] = enable && isa.extension_enabled(ext); } void set_impl(uint8_t impl, bool val) { impl_table[impl] = val; } bool supports_impl(uint8_t impl) const { @@ -319,7 +335,7 @@ public: } reg_t legalize_privilege(reg_t); void set_privilege(reg_t, bool); - const char* get_privilege_string(); + const char* get_privilege_string() const; void update_histogram(reg_t pc); const disassembler_t* get_disassembler() { return disassembler; } @@ -334,14 +350,15 @@ public: void register_extension(extension_t*); // MMIO slave interface - bool load(reg_t addr, size_t len, uint8_t* bytes); - bool store(reg_t addr, size_t len, const uint8_t* bytes); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; // When true, display disassembly of each instruction that's executed. bool debug; // When true, take the slow simulation path. - bool slow_path(); - bool halted() { return state.debug_mode; } + bool slow_path() const; + bool halted() const { return state.debug_mode; } enum { HR_NONE, /* Halt request is inactive. */ HR_REGULAR, /* Regular halt request/debug interrupt. */ @@ -361,8 +378,10 @@ public: void check_if_lpad_required(); + reg_t select_an_interrupt_with_default_priority(reg_t enabled_interrupts) const; + private: - const isa_parser_t * const isa; + const isa_parser_t isa; const cfg_t * const cfg; simif_t* sim; @@ -393,6 +412,10 @@ private: static const size_t OPCODE_CACHE_SIZE = 4095; opcode_cache_entry_t opcode_cache[OPCODE_CACHE_SIZE]; + unsigned ziccid_flush_count = 0; + static const unsigned ZICCID_FLUSH_PERIOD = 10; + + bool is_handled_in_vs(); void take_pending_interrupt() { take_interrupt(state.mip->read() & state.mie->read()); } void take_interrupt(reg_t mask); // take first enabled interrupt in mask void take_trap(trap_t& t, reg_t epc); // take an exception @@ -401,7 +424,7 @@ private: void register_insn(insn_desc_t, bool); int paddr_bits(); - void enter_debug_mode(uint8_t cause); + void enter_debug_mode(uint8_t cause, uint8_t ext_cause); void debug_output_log(std::stringstream *s); // either output to interactive user or write to log file diff --git a/riscv/riscv.ac b/riscv/riscv.ac index 378fd10..d848d9b 100644 --- a/riscv/riscv.ac +++ b/riscv/riscv.ac @@ -1,4 +1,4 @@ -AC_LANG_CPLUSPLUS +AC_LANG([C++]) AX_BOOST_BASE([1.53]) AX_BOOST_ASIO @@ -8,18 +8,6 @@ AC_CHECK_LIB([boost_system], [main], [], []) AC_CHECK_LIB([boost_regex], [main], [], []) -AC_ARG_WITH(isa, - [AS_HELP_STRING([--with-isa=RV64IMAFDC_zicntr_zihpm], - [Sets the default RISC-V ISA])], - AC_DEFINE_UNQUOTED([DEFAULT_ISA], "$withval", [Default value for --isa switch]), - AC_DEFINE_UNQUOTED([DEFAULT_ISA], "RV64IMAFDC_zicntr_zihpm", [Default value for --isa switch])) - -AC_ARG_WITH(priv, - [AS_HELP_STRING([--with-priv=MSU], - [Sets the default RISC-V privilege modes supported])], - AC_DEFINE_UNQUOTED([DEFAULT_PRIV], "$withval", [Default value for --priv switch]), - AC_DEFINE_UNQUOTED([DEFAULT_PRIV], "MSU", [Default value for --priv switch])) - AC_ARG_WITH(target, [AS_HELP_STRING([--with-target=riscv64-unknown-elf], [Sets the default target config])], diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 60723b5..4239a66 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -33,11 +33,13 @@ riscv_install_hdrs = \ entropy_source.h \ extension.h \ isa_parser.h \ + jtag_dtm.h \ log_file.h \ memtracer.h \ mmu.h \ platform.h \ processor.h \ + remote_bitbang.h \ rocc.h \ sim.h \ simif.h \ @@ -68,6 +70,7 @@ riscv_srcs = \ remote_bitbang.cc \ jtag_dtm.cc \ csrs.cc \ + csr_init.cc \ triggers.cc \ vector_unit.cc \ socketif.cc \ @@ -859,11 +862,21 @@ riscv_insn_ext_v_ctrl = \ vsetvli \ vsetvl \ +riscv_insn_ext_zvqdotq = \ + vqdot_vv \ + vqdot_vx \ + vqdotu_vv \ + vqdotu_vx \ + vqdotsu_vv \ + vqdotsu_vx \ + vqdotus_vx \ + riscv_insn_ext_v = \ $(riscv_insn_ext_v_alu_fp) \ $(riscv_insn_ext_v_alu_int) \ $(riscv_insn_ext_v_ctrl) \ $(riscv_insn_ext_v_ldst) \ + $(riscv_insn_ext_zvqdotq) \ riscv_insn_ext_h = \ hfence_gvma \ diff --git a/riscv/rocc.cc b/riscv/rocc.cc index 53ee051..9ba4fc1 100644 --- a/riscv/rocc.cc +++ b/riscv/rocc.cc @@ -14,15 +14,15 @@ u.i = insn; \ reg_t xs1 = u.r.xs1 ? RS1 : -1; \ reg_t xs2 = u.r.xs2 ? RS2 : -1; \ - reg_t xd = rocc->custom##n(u.r, xs1, xs2); \ + reg_t xd = rocc->custom##n(p, u.r, xs1, xs2); \ if (u.r.xd) \ WRITE_RD(xd); \ return pc+4; \ } \ \ - reg_t rocc_t::custom##n(rocc_insn_t UNUSED insn, reg_t UNUSED xs1, reg_t UNUSED xs2) \ + reg_t rocc_t::custom##n(processor_t *p, rocc_insn_t UNUSED insn, reg_t UNUSED xs1, reg_t UNUSED xs2) \ { \ - illegal_instruction(); \ + illegal_instruction(*p); \ return 0; \ } @@ -31,25 +31,17 @@ customX(1) customX(2) customX(3) -std::vector<insn_desc_t> rocc_t::get_instructions() +std::vector<insn_desc_t> rocc_t::get_instructions(const processor_t &) { - std::vector<insn_desc_t> insns; - insns.push_back((insn_desc_t){0x0b, 0x7f, - &::illegal_instruction, c0, &::illegal_instruction, c0, - &::illegal_instruction, c0, &::illegal_instruction, c0}); - insns.push_back((insn_desc_t){0x2b, 0x7f, - &::illegal_instruction, c1, &::illegal_instruction, c1, - &::illegal_instruction, c1, &::illegal_instruction, c1}); - insns.push_back((insn_desc_t){0x5b, 0x7f, - &::illegal_instruction, c2, &::illegal_instruction, c2, - &::illegal_instruction, c2, &::illegal_instruction, c2}); - insns.push_back((insn_desc_t){0x7b, 0x7f, - &::illegal_instruction, c3, &::illegal_instruction, c3, - &::illegal_instruction, c0, &::illegal_instruction, c3}); + std::vector<insn_desc_t> insns = { + {0x0b, 0x7f, &::illegal_instruction, c0, &::illegal_instruction, c0, &::illegal_instruction, c0, &::illegal_instruction, c0}, + {0x2b, 0x7f, &::illegal_instruction, c1, &::illegal_instruction, c1, &::illegal_instruction, c1, &::illegal_instruction, c1}, + {0x5b, 0x7f, &::illegal_instruction, c2, &::illegal_instruction, c2, &::illegal_instruction, c2, &::illegal_instruction, c2}, + {0x7b, 0x7f, &::illegal_instruction, c3, &::illegal_instruction, c3, &::illegal_instruction, c0, &::illegal_instruction, c3}}; return insns; } -std::vector<disasm_insn_t*> rocc_t::get_disasms() +std::vector<disasm_insn_t *> rocc_t::get_disasms(const processor_t *) { std::vector<disasm_insn_t*> insns; return insns; diff --git a/riscv/rocc.h b/riscv/rocc.h index d65ec97..d7fee26 100644 --- a/riscv/rocc.h +++ b/riscv/rocc.h @@ -24,12 +24,12 @@ union rocc_insn_union_t class rocc_t : public extension_t { public: - virtual reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom1(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom2(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom3(rocc_insn_t insn, reg_t xs1, reg_t xs2); - std::vector<insn_desc_t> get_instructions(); - std::vector<disasm_insn_t*> get_disasms(); + virtual reg_t custom0(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom1(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom2(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom3(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + std::vector<insn_desc_t> get_instructions(const processor_t &proc) override; + std::vector<disasm_insn_t *> get_disasms(const processor_t *proc = nullptr) override; }; #define define_custom_func(type_name, ext_name_str, func_name, method_name) \ diff --git a/riscv/sim.cc b/riscv/sim.cc index d08e274..388d729 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -44,15 +44,15 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, const char *log_path, bool dtb_enabled, const char *dtb_file, bool socket_enabled, - FILE *cmd_file) // needed for command line option --cmd + FILE *cmd_file, // needed for command line option --cmd + std::optional<unsigned long long> instruction_limit) : htif_t(args), - isa(cfg->isa, cfg->priv), cfg(cfg), mems(mems), - procs(std::max(cfg->nprocs(), size_t(1))), dtb_enabled(dtb_enabled), log_file(log_path), cmd_file(cmd_file), + instruction_limit(instruction_limit), sout_(nullptr), current_step(0), current_proc(0), @@ -96,16 +96,18 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, } #endif - debug_mmu = new mmu_t(this, cfg->endianness, NULL); - - for (size_t i = 0; i < cfg->nprocs(); i++) { - procs[i] = new processor_t(&isa, cfg, this, cfg->hartids[i], halted, - log_file.get(), sout_); - harts[cfg->hartids[i]] = procs[i]; - } + debug_mmu = new mmu_t(this, cfg->endianness, NULL, cfg->cache_blocksz); // When running without using a dtb, skip the fdt-based configuration steps - if (!dtb_enabled) return; + if (!dtb_enabled) { + for (size_t i = 0; i < cfg->nprocs(); i++) { + procs.push_back(new processor_t(cfg->isa, cfg->priv, + cfg, this, cfg->hartids[i], halted, + log_file.get(), sout_)); + harts[cfg->hartids[i]] = procs[i]; + } + return; + } // otherwise, generate the procs by parsing the DTS // Only make a CLINT (Core-Local INTerrupt controller) and PLIC (Platform- // Level-Interrupt-Controller) if they are specified in the device tree @@ -133,19 +135,16 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, std::stringstream strstream; strstream << fin.rdbuf(); dtb = strstream.str(); + dts = dtb_to_dts(dtb); } else { - std::pair<reg_t, reg_t> initrd_bounds = cfg->initrd_bounds; std::string device_nodes; for (const device_factory_sargs_t& factory_sargs: device_factories) { const device_factory_t* factory = factory_sargs.first; const std::vector<std::string>& sargs = factory_sargs.second; device_nodes.append(factory->generate_dts(this, sargs)); } - dts = make_dts(INSNS_PER_RTC_TICK, CPU_HZ, - initrd_bounds.first, initrd_bounds.second, - cfg->bootargs, cfg->pmpregions, cfg->pmpgranularity, - procs, mems, device_nodes); - dtb = dts_compile(dts); + dts = make_dts(INSNS_PER_RTC_TICK, CPU_HZ, cfg, mems, device_nodes); + dtb = dts_to_dtb(dts); } int fdt_code = fdt_check_header(dtb.c_str()); @@ -162,24 +161,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, void *fdt = (void *)dtb.c_str(); - for (size_t i = 0; i < device_factories.size(); i++) { - const device_factory_t* factory = device_factories[i].first; - const std::vector<std::string>& sargs = device_factories[i].second; - reg_t device_base = 0; - abstract_device_t* device = factory->parse_from_fdt(fdt, this, &device_base, sargs); - if (device) { - assert(device_base); - std::shared_ptr<abstract_device_t> dev_ptr(device); - add_device(device_base, dev_ptr); - - if (i == 0) // clint_factory - clint = std::static_pointer_cast<clint_t>(dev_ptr); - else if (i == 1) // plic_factory - plic = std::static_pointer_cast<plic_t>(dev_ptr); - } - } - - //per core attribute + // per core attribute int cpu_offset = 0, cpu_map_offset, rc; size_t cpu_idx = 0; cpu_offset = fdt_get_offset(fdt, "/cpus"); @@ -193,10 +175,33 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, if (!(cpu_map_offset < 0) && cpu_offset == cpu_map_offset) continue; - if (cpu_idx >= nprocs()) - break; + if (cpu_idx != procs.size()) { + std::cerr << "Spike only supports contiguous CPU IDs in the DTS" << std::endl; + exit(1); + } + + // handle isa string + const char* isa_str; + rc = fdt_parse_isa(fdt, cpu_offset, &isa_str); + if (rc != 0) { + std::cerr << "core (" << cpu_idx << ") has an invalid or missing 'riscv,isa'\n"; + exit(1); + } + + // handle hartid + uint32_t hartid; + rc = fdt_parse_hartid(fdt, cpu_offset, &hartid); + if (rc != 0) { + std::cerr << "core (" << cpu_idx << ") has an invalid or missing `reg` (hartid)\n"; + exit(1); + } - //handle pmp + procs.push_back(new processor_t(isa_str, cfg->priv, + cfg, this, hartid, halted, + log_file.get(), sout_)); + harts[hartid] = procs[cpu_idx]; + + // handle pmp reg_t pmp_num, pmp_granularity; if (fdt_parse_pmp_num(fdt, cpu_offset, &pmp_num) != 0) pmp_num = 0; @@ -206,7 +211,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, procs[cpu_idx]->set_pmp_granularity(pmp_granularity); } - //handle mmu-type + // handle mmu-type const char *mmu_type; rc = fdt_parse_mmu_type(fdt, cpu_offset, &mmu_type); if (rc == 0) { @@ -220,7 +225,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, } else if (strncmp(mmu_type, "riscv,sv57", strlen("riscv,sv57")) == 0) { procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV57); } else if (strncmp(mmu_type, "riscv,sbare", strlen("riscv,sbare")) == 0) { - //has been set in the beginning + // has been set in the beginning } else { std::cerr << "core (" << cpu_idx @@ -232,15 +237,27 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SBARE); } + procs[cpu_idx]->reset(); + cpu_idx++; } - if (cpu_idx != nprocs()) { - std::cerr << "core number in dts (" - << cpu_idx - << ") doesn't match it in command line (" - << nprocs() << ").\n"; - exit(1); + // must be located after procs/harts are set (devices might use sim_t get_* member functions) + for (size_t i = 0; i < device_factories.size(); i++) { + const device_factory_t* factory = device_factories[i].first; + const std::vector<std::string>& sargs = device_factories[i].second; + reg_t device_base = 0; + abstract_device_t* device = factory->parse_from_fdt(fdt, this, &device_base, sargs); + if (device) { + assert(device_base); + std::shared_ptr<abstract_device_t> dev_ptr(device); + add_device(device_base, dev_ptr); + + if (i == 0) // clint_factory + clint = std::static_pointer_cast<clint_t>(dev_ptr); + else if (i == 1) // plic_factory + plic = std::static_pointer_cast<plic_t>(dev_ptr); + } } } @@ -256,7 +273,7 @@ int sim_t::run() if (!debug && log) set_procs_debug(true); - htif_t::set_expected_xlen(isa.get_max_xlen()); + htif_t::set_expected_xlen(harts[0]->get_isa().get_max_xlen()); // htif_t::run() will repeatedly call back into sim_t::idle(), each // invocation of which will advance target time @@ -322,7 +339,8 @@ void sim_t::set_procs_debug(bool value) static bool paddr_ok(reg_t addr) { - return (addr >> MAX_PADDR_BITS) == 0; + static_assert(MAX_PADDR_BITS == 8 * sizeof(addr)); + return true; } bool sim_t::mmio_load(reg_t paddr, size_t len, uint8_t* bytes) @@ -387,10 +405,9 @@ void sim_t::set_rom() char* sim_t::addr_to_mem(reg_t paddr) { if (!paddr_ok(paddr)) return NULL; - auto desc = bus.find_device(paddr); + auto desc = bus.find_device(paddr >> PGSHIFT << PGSHIFT, PGSIZE); if (auto mem = dynamic_cast<abstract_mem_t*>(desc.second)) - if (paddr - desc.first < mem->size()) - return mem->contents(paddr - desc.first); + return mem->contents(paddr - desc.first); return NULL; } @@ -414,8 +431,19 @@ void sim_t::idle() if (debug || ctrlc_pressed) interactive(); - else + else { + if (instruction_limit.has_value()) { + if (*instruction_limit < INTERLEAVE) { + // Final step. + step(*instruction_limit); + htif_exit(0); + *instruction_limit = 0; + return; + } + *instruction_limit -= INTERLEAVE; + } step(INTERLEAVE); + } if (remote_bitbang) remote_bitbang->tick(); diff --git a/riscv/sim.h b/riscv/sim.h index 540d80d..da04a88 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -35,10 +35,10 @@ public: const debug_module_config_t &dm_config, const char *log_path, bool dtb_enabled, const char *dtb_file, bool socket_enabled, - FILE *cmd_file); // needed for command line option --cmd + FILE *cmd_file, // needed for command line option --cmd + std::optional<unsigned long long> instruction_limit); ~sim_t(); - // run the simulation to completion int run(); void set_debug(bool value); void set_histogram(bool value); @@ -69,7 +69,6 @@ public: static const size_t CPU_HZ = 1000000000; // 1GHz CPU private: - isa_parser_t isa; const cfg_t * const cfg; std::vector<std::pair<reg_t, abstract_mem_t*>> mems; std::vector<processor_t*> procs; @@ -86,6 +85,8 @@ private: FILE *cmd_file; // pointer to debug command input file + std::optional<unsigned long long> instruction_limit; + socketif_t *socketif; std::ostream sout_; // used for socket and terminal interface @@ -99,8 +100,13 @@ private: remote_bitbang_t* remote_bitbang; std::optional<std::function<void()>> next_interactive_action; - // memory-mapped I/O routines + // If padd corresponds to memory (as opposed to an I/O device), return a + // host pointer corresponding to paddr. + // For these purposes, only memories that include the entire base page + // surrounding paddr are considered; smaller memories are treated as I/O. virtual char* addr_to_mem(reg_t paddr) override; + + // memory-mapped I/O routines virtual bool mmio_load(reg_t paddr, size_t len, uint8_t* bytes) override; virtual bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes) override; void set_rom(); diff --git a/riscv/trap.h b/riscv/trap.h index 5eb62cf..5ea56e2 100644 --- a/riscv/trap.h +++ b/riscv/trap.h @@ -115,6 +115,7 @@ DECLARE_TRAP(CAUSE_MACHINE_ECALL, machine_ecall) DECLARE_MEM_TRAP(CAUSE_FETCH_PAGE_FAULT, instruction_page_fault) DECLARE_MEM_TRAP(CAUSE_LOAD_PAGE_FAULT, load_page_fault) DECLARE_MEM_TRAP(CAUSE_STORE_PAGE_FAULT, store_page_fault) +DECLARE_TRAP(CAUSE_DOUBLE_TRAP, double_trap) DECLARE_MEM_GVA_TRAP(CAUSE_FETCH_GUEST_PAGE_FAULT, instruction_guest_page_fault) DECLARE_MEM_GVA_TRAP(CAUSE_LOAD_GUEST_PAGE_FAULT, load_guest_page_fault) DECLARE_INST_TRAP(CAUSE_VIRTUAL_INSTRUCTION, virtual_instruction) diff --git a/riscv/triggers.cc b/riscv/triggers.cc index de3da40..9c21330 100644 --- a/riscv/triggers.cc +++ b/riscv/triggers.cc @@ -52,15 +52,57 @@ void trigger_t::tdata3_write(processor_t * const proc, const reg_t val) noexcept mhselect = get_field(val, CSR_TEXTRA_MHSELECT(xlen)); sbytemask = get_field(val, CSR_TEXTRA_SBYTEMASK(xlen)); svalue = proc->extension_enabled_const('S') ? get_field(val, CSR_TEXTRA_SVALUE(xlen)) : 0; - sselect = (sselect_t)((proc->extension_enabled_const('S') && get_field(val, CSR_TEXTRA_SSELECT(xlen)) <= SSELECT_MAXVAL) ? get_field(val, CSR_TEXTRA_SSELECT(xlen)) : SSELECT_IGNORE); + sselect = (sselect_t)((proc->extension_enabled_const('S') && get_field(val, CSR_TEXTRA_SSELECT(xlen)) <= SSELECT_MAXVAL) ? get_field(val, CSR_TEXTRA_SSELECT(xlen)) : (reg_t)SSELECT_IGNORE); +} + +static reg_t tcontrol_value(const state_t * state) { + if (state->tcontrol) + return state->tcontrol->read(); + else + return 0; } bool trigger_t::common_match(processor_t * const proc, bool use_prev_prv) const noexcept { auto state = proc->get_state(); auto prv = use_prev_prv ? state->prev_prv : state->prv; auto v = use_prev_prv ? state->prev_v : state->v; - auto m_enabled = get_action() != 0 || (state->tcontrol->read() & CSR_TCONTROL_MTE); - return (prv < PRV_M || m_enabled) && mode_match(prv, v) && textra_match(proc); + + if (!mode_match(prv, v)) + return false; + + if (!textra_match(proc)) + return false; + + if (get_action() == ACTION_DEBUG_EXCEPTION) { + if (proc->extension_enabled('S')) { + // The hardware prevents triggers with action=0 from matching or firing + // while in M-mode and while MIE in mstatus is 0. If medeleg [3]=1 then it + // prevents triggers with action=0 from matching or firing while in S-mode + // and while SIE in sstatus is 0. If medeleg [3]=1 and hedeleg [3]=1 then + // it prevents triggers with action=0 from matching or firing while in + // VS-mode and while SIE in vstatus is 0. + + const bool mstatus_mie = state->mstatus->read() & MSTATUS_MIE; + if (prv == PRV_M && !mstatus_mie) + return false; + + const bool sstatus_sie = state->sstatus->read() & MSTATUS_SIE; + const bool medeleg_breakpoint = (state->medeleg->read() >> CAUSE_BREAKPOINT) & 1; + if (prv == PRV_S && !v && medeleg_breakpoint && !sstatus_sie) + return false; + + const bool vsstatus_sie = state->vsstatus->read() & MSTATUS_SIE; + const bool hedeleg_breakpoint = (state->hedeleg->read() >> CAUSE_BREAKPOINT) & 1; + if (prv == PRV_S && v && medeleg_breakpoint && hedeleg_breakpoint && !vsstatus_sie) + return false; + } else { + // mte and mpte in tcontrol is implemented. medeleg [3] is hard-wired to 0. + if (prv == PRV_M && !(tcontrol_value(state) & CSR_TCONTROL_MTE)) + return false; + } + } + + return true; } bool trigger_t::mode_match(reg_t prv, bool v) const noexcept @@ -110,21 +152,6 @@ bool trigger_t::textra_match(processor_t * const proc) const noexcept return true; } -bool trigger_t::allow_action(const state_t * const state) const -{ - if (get_action() == ACTION_DEBUG_EXCEPTION) { - const bool mstatus_mie = state->mstatus->read() & MSTATUS_MIE; - const bool sstatus_sie = state->sstatus->read() & MSTATUS_SIE; - const bool vsstatus_sie = state->vsstatus->read() & MSTATUS_SIE; - const bool medeleg_breakpoint = (state->medeleg->read() >> CAUSE_BREAKPOINT) & 1; - const bool hedeleg_breakpoint = (state->hedeleg->read() >> CAUSE_BREAKPOINT) & 1; - return (state->prv != PRV_M || mstatus_mie) && - (state->prv != PRV_S || state->v || !medeleg_breakpoint || sstatus_sie) && - (state->prv != PRV_S || !state->v || !medeleg_breakpoint || !hedeleg_breakpoint || vsstatus_sie); - } - return true; -} - reg_t disabled_trigger_t::tdata1_read(const processor_t * const proc) const noexcept { auto xlen = proc->get_xlen(); @@ -146,7 +173,7 @@ reg_t mcontrol_t::tdata1_read(const processor_t * const proc) const noexcept { auto xlen = proc->get_xlen(); v = set_field(v, MCONTROL_TYPE(xlen), CSR_TDATA1_TYPE_MCONTROL); v = set_field(v, CSR_MCONTROL_DMODE(xlen), dmode); - v = set_field(v, MCONTROL_MASKMAX(xlen), 0); + v = set_field(v, MCONTROL_MASKMAX(xlen), maskmax); v = set_field(v, CSR_MCONTROL_HIT, hit); v = set_field(v, MCONTROL_SELECT, select); v = set_field(v, MCONTROL_TIMING, timing); @@ -171,7 +198,7 @@ void mcontrol_t::tdata1_write(processor_t * const proc, const reg_t val, const b timing = legalize_timing(val, MCONTROL_TIMING, MCONTROL_SELECT, MCONTROL_EXECUTE, MCONTROL_LOAD); action = legalize_action(val, MCONTROL_ACTION, CSR_MCONTROL_DMODE(xlen)); chain = allow_chain ? get_field(val, MCONTROL_CHAIN) : 0; - match = legalize_match(get_field(val, MCONTROL_MATCH)); + match = legalize_match(get_field(val, MCONTROL_MATCH), maskmax); m = get_field(val, MCONTROL_M); s = proc->extension_enabled_const('S') ? get_field(val, CSR_MCONTROL_S) : 0; u = proc->extension_enabled_const('U') ? get_field(val, CSR_MCONTROL_U) : 0; @@ -195,13 +222,17 @@ bool mcontrol_common_t::simple_match(unsigned xlen, reg_t value) const { return value < tdata2; case MATCH_MASK_LOW: { - reg_t mask = tdata2 >> (xlen/2); - return (value & mask) == (tdata2 & mask); + reg_t tdata2_high = tdata2 >> (xlen/2); + reg_t tdata2_low = tdata2 & ((reg_t(1) << (xlen/2)) - 1); + reg_t value_low = value & ((reg_t(1) << (xlen/2)) - 1); + return (value_low & tdata2_high) == tdata2_low; } case MATCH_MASK_HIGH: { - reg_t mask = tdata2 >> (xlen/2); - return ((value >> (xlen/2)) & mask) == (tdata2 & mask); + reg_t tdata2_high = tdata2 >> (xlen/2); + reg_t tdata2_low = tdata2 & ((reg_t(1) << (xlen/2)) - 1); + reg_t value_high = value >> (xlen/2); + return (value_high & tdata2_high) == tdata2_low; } } assert(0); @@ -231,7 +262,7 @@ std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(proc value &= 0xffffffff; } - if (simple_match(xlen, value) && allow_action(proc->get_state())) { + if (simple_match(xlen, value)) { /* This is OK because this function is only called if the trigger was not * inhibited by the previous trigger in the chain. */ set_hit(timing ? HIT_IMMEDIATELY_AFTER : HIT_BEFORE); @@ -240,11 +271,14 @@ std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(proc return std::nullopt; } -mcontrol_common_t::match_t mcontrol_common_t::legalize_match(reg_t val) noexcept +mcontrol_common_t::match_t mcontrol_common_t::legalize_match(reg_t val, reg_t maskmax) noexcept { switch (val) { - case MATCH_EQUAL: case MATCH_NAPOT: + if (maskmax == 0) + return MATCH_EQUAL; + [[fallthrough]]; + case MATCH_EQUAL: case MATCH_GE: case MATCH_LT: case MATCH_MASK_LOW: @@ -261,7 +295,14 @@ bool mcontrol_common_t::legalize_timing(reg_t val, reg_t timing_mask, reg_t sele return TIMING_AFTER; if (get_field(val, execute_mask)) return TIMING_BEFORE; - return get_field(val, timing_mask); + if (timing_mask) { + // Use the requested timing. + return get_field(val, timing_mask); + } else { + // For mcontrol6 you can't request a timing. Default to before since that's + // most useful to the user. + return TIMING_BEFORE; + } } reg_t mcontrol6_t::tdata1_read(const processor_t * const proc) const noexcept { @@ -290,13 +331,14 @@ void mcontrol6_t::tdata1_write(processor_t * const proc, const reg_t val, const auto xlen = proc->get_const_xlen(); assert(get_field(val, CSR_MCONTROL6_TYPE(xlen)) == CSR_TDATA1_TYPE_MCONTROL6); dmode = get_field(val, CSR_MCONTROL6_DMODE(xlen)); + const reg_t maskmax6 = xlen - 1; vs = get_field(val, CSR_MCONTROL6_VS); vu = get_field(val, CSR_MCONTROL6_VU); hit = hit_t(2 * get_field(val, CSR_MCONTROL6_HIT1) + get_field(val, CSR_MCONTROL6_HIT0)); // 2-bit field {hit1,hit0} select = get_field(val, CSR_MCONTROL6_SELECT); action = legalize_action(val, CSR_MCONTROL6_ACTION, CSR_MCONTROL6_DMODE(xlen)); chain = allow_chain ? get_field(val, CSR_MCONTROL6_CHAIN) : 0; - match = legalize_match(get_field(val, CSR_MCONTROL6_MATCH)); + match = legalize_match(get_field(val, CSR_MCONTROL6_MATCH), maskmax6); m = get_field(val, CSR_MCONTROL6_M); s = proc->extension_enabled_const('S') ? get_field(val, CSR_MCONTROL6_S) : 0; u = proc->extension_enabled_const('U') ? get_field(val, CSR_MCONTROL6_U) : 0; @@ -312,7 +354,7 @@ void mcontrol6_t::tdata1_write(processor_t * const proc, const reg_t val, const std::optional<match_result_t> icount_t::detect_icount_fire(processor_t * const proc) noexcept { - if (!common_match(proc) || !allow_action(proc->get_state())) + if (!common_match(proc)) return std::nullopt; std::optional<match_result_t> ret = std::nullopt; @@ -327,7 +369,7 @@ std::optional<match_result_t> icount_t::detect_icount_fire(processor_t * const p void icount_t::detect_icount_decrement(processor_t * const proc) noexcept { - if (!common_match(proc) || !allow_action(proc->get_state())) + if (!common_match(proc)) return; if (count >= 1) { @@ -419,7 +461,7 @@ std::optional<match_result_t> trap_common_t::detect_trap_match(processor_t * con bool interrupt = (t.cause() & ((reg_t)1 << (xlen - 1))) != 0; reg_t bit = t.cause() & ~((reg_t)1 << (xlen - 1)); assert(bit < xlen); - if (simple_match(interrupt, bit) && allow_action(proc->get_state())) { + if (simple_match(interrupt, bit)) { hit = true; return match_result_t(TIMING_AFTER, action); } @@ -636,4 +678,4 @@ reg_t module_t::tinfo_read(unsigned UNUSED index) const noexcept (CSR_TINFO_VERSION_1 << CSR_TINFO_VERSION_OFFSET); } -}; +} diff --git a/riscv/triggers.h b/riscv/triggers.h index 24f9206..60ee5ca 100644 --- a/riscv/triggers.h +++ b/riscv/triggers.h @@ -99,7 +99,6 @@ public: protected: static action_t legalize_action(reg_t val, reg_t action_mask, reg_t dmode_mask) noexcept; bool common_match(processor_t * const proc, bool use_prev_prv = false) const noexcept; - bool allow_action(const state_t * const state) const; reg_t tdata2; bool vs = false; @@ -221,7 +220,7 @@ private: bool simple_match(unsigned xlen, reg_t value) const; protected: - static match_t legalize_match(reg_t val) noexcept; + static match_t legalize_match(reg_t val, reg_t maskmax) noexcept; static bool legalize_timing(reg_t val, reg_t timing_mask, reg_t select_mask, reg_t execute_mask, reg_t load_mask) noexcept; bool dmode = false; action_t action = ACTION_DEBUG_EXCEPTION; @@ -243,6 +242,7 @@ public: private: bool hit = false; + const reg_t maskmax = 0; }; class mcontrol6_t : public mcontrol_common_t { @@ -301,6 +301,6 @@ private: std::vector<trigger_t *> triggers; }; -}; +} #endif diff --git a/riscv/v_ext_macros.h b/riscv/v_ext_macros.h index 3e8a653..1e33232 100644 --- a/riscv/v_ext_macros.h +++ b/riscv/v_ext_macros.h @@ -8,16 +8,10 @@ // // vector: masking skip helper // -#define VI_MASK_VARS \ - const int midx = i / 64; \ - const int mpos = i % 64; - #define VI_LOOP_ELEMENT_SKIP(BODY) \ - VI_MASK_VARS \ if (insn.v_vm() == 0) { \ BODY; \ - bool skip = ((P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1) == 0; \ - if (skip) { \ + if (!P.VU.mask_elt(0, i)) { \ continue; \ } \ } @@ -206,7 +200,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, require_vector(true); \ reg_t vl = P.VU.vl->read(); \ reg_t UNUSED sew = P.VU.vsew; \ - reg_t rd_num = insn.rd(); \ + reg_t UNUSED rd_num = insn.rd(); \ reg_t UNUSED rs1_num = insn.rs1(); \ reg_t rs2_num = insn.rs2(); \ for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { @@ -231,24 +225,18 @@ static inline bool is_overlapped_widen(const int astart, int asize, #define VI_LOOP_CARRY_BASE \ VI_GENERAL_LOOP_BASE \ - VI_MASK_VARS \ - auto v0 = P.VU.elt<uint64_t>(0, midx); \ - const uint64_t mmask = UINT64_C(1) << mpos; \ const uint128_t op_mask = (UINT64_MAX >> (64 - sew)); \ - uint64_t carry = insn.v_vm() == 0 ? (v0 >> mpos) & 0x1 : 0; \ - uint128_t res = 0; \ - auto &vd = P.VU.elt<uint64_t>(rd_num, midx, true); + uint64_t carry = insn.v_vm() == 0 ? P.VU.mask_elt(0, i) : 0; \ + bool res = false; #define VI_LOOP_CARRY_END \ - vd = (vd & ~mmask) | (((res) << mpos) & mmask); \ + P.VU.set_mask_elt(insn.rd(), i, res); \ } \ P.VU.vstart->write(0); #define VI_LOOP_WITH_CARRY_BASE \ VI_GENERAL_LOOP_BASE \ - VI_MASK_VARS \ - auto &v0 = P.VU.elt<uint64_t>(0, midx); \ const uint128_t op_mask = (UINT64_MAX >> (64 - sew)); \ - uint64_t carry = (v0 >> mpos) & 0x1; + uint64_t carry = P.VU.mask_elt(0, i); #define VI_LOOP_CMP_BASE \ require(P.VU.vsew >= e8 && P.VU.vsew <= e64); \ @@ -260,12 +248,10 @@ static inline bool is_overlapped_widen(const int astart, int asize, reg_t rs2_num = insn.rs2(); \ for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { \ VI_LOOP_ELEMENT_SKIP(); \ - uint64_t mmask = UINT64_C(1) << mpos; \ - uint64_t &vdi = P.VU.elt<uint64_t>(insn.rd(), midx, true); \ - uint64_t res = 0; + bool res = false; #define VI_LOOP_CMP_END \ - vdi = (vdi & ~mmask) | (((res) << mpos) & mmask); \ + P.VU.set_mask_elt(insn.rd(), i, res); \ } \ P.VU.vstart->write(0); @@ -274,13 +260,9 @@ static inline bool is_overlapped_widen(const int astart, int asize, require_vector(true); \ reg_t vl = P.VU.vl->read(); \ for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { \ - int midx = i / 64; \ - int mpos = i % 64; \ - uint64_t mmask = UINT64_C(1) << mpos; \ - uint64_t vs2 = P.VU.elt<uint64_t>(insn.rs2(), midx); \ - uint64_t vs1 = P.VU.elt<uint64_t>(insn.rs1(), midx); \ - uint64_t &res = P.VU.elt<uint64_t>(insn.rd(), midx, true); \ - res = (res & ~mmask) | ((op) & (1ULL << mpos)); \ + bool vs2 = P.VU.mask_elt(insn.rs2(), i); \ + bool vs1 = P.VU.mask_elt(insn.rs1(), i); \ + P.VU.set_mask_elt(insn.rd(), i, (op)); \ } \ P.VU.vstart->write(0); @@ -354,7 +336,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, #define VI_PARAMS(x) \ type_sew_t<x>::type &vd = P.VU.elt<type_sew_t<x>::type>(rd_num, i, true); \ - type_sew_t<x>::type simm5 = (type_sew_t<x>::type)insn.v_simm5(); \ + type_sew_t<x>::type UNUSED simm5 = (type_sew_t<x>::type)insn.v_simm5(); \ type_sew_t<x>::type UNUSED vs2 = P.VU.elt<type_sew_t<x>::type>(rs2_num, i); #define XV_PARAMS(x) \ @@ -454,7 +436,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, #define VFP_VF_CMP_PARAMS(width) \ float##width##_t rs1 = f##width(READ_FREG(rs1_num)); \ - float##width##_t vs2 = P.VU.elt<float##width##_t>(rs2_num, i); + float##width##_t UNUSED vs2 = P.VU.elt<float##width##_t>(rs2_num, i); #define VFP_VF_PARAMS(width) \ float##width##_t &vd = P.VU.elt<float##width##_t>(rd_num, i, true); \ @@ -491,7 +473,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, BODY; \ } -// comparision result to masking register +// comparison result to masking register #define VI_LOOP_CMP_BODY(PARAMS, BODY) \ VI_LOOP_CMP_BASE \ INSNS_BASE(PARAMS, BODY) \ @@ -523,8 +505,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, // merge and copy loop #define VI_MERGE_VARS \ - VI_MASK_VARS \ - bool UNUSED use_first = (P.VU.elt<uint64_t>(0, midx) >> mpos) & 0x1; + bool UNUSED use_first = P.VU.mask_elt(0, i); #define VI_MERGE_LOOP_BASE \ VI_GENERAL_LOOP_BASE \ @@ -1144,32 +1125,32 @@ static inline bool is_overlapped_widen(const int astart, int asize, // average loop #define VI_VV_LOOP_AVG(op) \ -VRM xrm = p->VU.get_vround_mode(); \ VI_VV_LOOP({ \ + VRM xrm = p->VU.get_vround_mode(); \ uint128_t res = ((uint128_t)vs2) op vs1; \ INT_ROUNDING(res, xrm, 1); \ vd = res >> 1; \ }) #define VI_VX_LOOP_AVG(op) \ -VRM xrm = p->VU.get_vround_mode(); \ VI_VX_LOOP({ \ + VRM xrm = p->VU.get_vround_mode(); \ uint128_t res = ((uint128_t)vs2) op rs1; \ INT_ROUNDING(res, xrm, 1); \ vd = res >> 1; \ }) #define VI_VV_ULOOP_AVG(op) \ -VRM xrm = p->VU.get_vround_mode(); \ VI_VV_ULOOP({ \ + VRM xrm = p->VU.get_vround_mode(); \ uint128_t res = ((uint128_t)vs2) op vs1; \ INT_ROUNDING(res, xrm, 1); \ vd = res >> 1; \ }) #define VI_VX_ULOOP_AVG(op) \ -VRM xrm = p->VU.get_vround_mode(); \ VI_VX_ULOOP({ \ + VRM xrm = p->VU.get_vround_mode(); \ uint128_t res = ((uint128_t)vs2) op rs1; \ INT_ROUNDING(res, xrm, 1); \ vd = res >> 1; \ @@ -1181,31 +1162,12 @@ VI_VX_ULOOP({ \ #define VI_STRIP(inx) \ reg_t vreg_inx = inx; -#define VI_DUPLICATE_VREG(reg_num, idx_sew) \ -reg_t index[P.VU.vlmax]; \ - for (reg_t i = 0; i < P.VU.vlmax && P.VU.vl->read() != 0; ++i) { \ - switch (idx_sew) { \ - case e8: \ - index[i] = P.VU.elt<uint8_t>(reg_num, i); \ - break; \ - case e16: \ - index[i] = P.VU.elt<uint16_t>(reg_num, i); \ - break; \ - case e32: \ - index[i] = P.VU.elt<uint32_t>(reg_num, i); \ - break; \ - case e64: \ - index[i] = P.VU.elt<uint64_t>(reg_num, i); \ - break; \ - } \ -} - #define VI_LD(stride, offset, elt_width, is_mask_ldst) \ const reg_t nf = insn.v_nf() + 1; \ + VI_CHECK_LOAD(elt_width, is_mask_ldst); \ const reg_t vl = is_mask_ldst ? ((P.VU.vl->read() + 7) / 8) : P.VU.vl->read(); \ const reg_t baseAddr = RS1; \ const reg_t vd = insn.rd(); \ - VI_CHECK_LOAD(elt_width, is_mask_ldst); \ for (reg_t i = 0; i < vl; ++i) { \ VI_ELEMENT_SKIP; \ VI_STRIP(i); \ @@ -1218,16 +1180,33 @@ reg_t index[P.VU.vlmax]; \ } \ P.VU.vstart->write(0); +#define VI_LDST_GET_INDEX(elt_width) \ + reg_t index; \ + switch (elt_width) { \ + case e8: \ + index = P.VU.elt<uint8_t>(insn.rs2(), i); \ + break; \ + case e16: \ + index = P.VU.elt<uint16_t>(insn.rs2(), i); \ + break; \ + case e32: \ + index = P.VU.elt<uint32_t>(insn.rs2(), i); \ + break; \ + case e64: \ + index = P.VU.elt<uint64_t>(insn.rs2(), i); \ + break; \ + } \ + #define VI_LD_INDEX(elt_width, is_seg) \ const reg_t nf = insn.v_nf() + 1; \ + VI_CHECK_LD_INDEX(elt_width); \ const reg_t vl = P.VU.vl->read(); \ const reg_t baseAddr = RS1; \ const reg_t vd = insn.rd(); \ if (!is_seg) \ require(nf == 1); \ - VI_CHECK_LD_INDEX(elt_width); \ - VI_DUPLICATE_VREG(insn.rs2(), elt_width); \ for (reg_t i = 0; i < vl; ++i) { \ + VI_LDST_GET_INDEX(elt_width); \ VI_ELEMENT_SKIP; \ VI_STRIP(i); \ P.VU.vstart->write(i); \ @@ -1235,19 +1214,19 @@ reg_t index[P.VU.vlmax]; \ switch (P.VU.vsew) { \ case e8: \ P.VU.elt<uint8_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint8_t>(baseAddr + index[i] + fn * 1); \ + MMU.load<uint8_t>(baseAddr + index + fn * 1); \ break; \ case e16: \ P.VU.elt<uint16_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint16_t>(baseAddr + index[i] + fn * 2); \ + MMU.load<uint16_t>(baseAddr + index + fn * 2); \ break; \ case e32: \ P.VU.elt<uint32_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint32_t>(baseAddr + index[i] + fn * 4); \ + MMU.load<uint32_t>(baseAddr + index + fn * 4); \ break; \ default: \ P.VU.elt<uint64_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint64_t>(baseAddr + index[i] + fn * 8); \ + MMU.load<uint64_t>(baseAddr + index + fn * 8); \ break; \ } \ } \ @@ -1256,10 +1235,10 @@ reg_t index[P.VU.vlmax]; \ #define VI_ST(stride, offset, elt_width, is_mask_ldst) \ const reg_t nf = insn.v_nf() + 1; \ + VI_CHECK_STORE(elt_width, is_mask_ldst); \ const reg_t vl = is_mask_ldst ? ((P.VU.vl->read() + 7) / 8) : P.VU.vl->read(); \ const reg_t baseAddr = RS1; \ const reg_t vs3 = insn.rd(); \ - VI_CHECK_STORE(elt_width, is_mask_ldst); \ for (reg_t i = 0; i < vl; ++i) { \ VI_STRIP(i) \ VI_ELEMENT_SKIP; \ @@ -1274,33 +1253,33 @@ reg_t index[P.VU.vlmax]; \ #define VI_ST_INDEX(elt_width, is_seg) \ const reg_t nf = insn.v_nf() + 1; \ + VI_CHECK_ST_INDEX(elt_width); \ const reg_t vl = P.VU.vl->read(); \ const reg_t baseAddr = RS1; \ const reg_t vs3 = insn.rd(); \ if (!is_seg) \ require(nf == 1); \ - VI_CHECK_ST_INDEX(elt_width); \ - VI_DUPLICATE_VREG(insn.rs2(), elt_width); \ for (reg_t i = 0; i < vl; ++i) { \ + VI_LDST_GET_INDEX(elt_width); \ VI_STRIP(i) \ VI_ELEMENT_SKIP; \ P.VU.vstart->write(i); \ for (reg_t fn = 0; fn < nf; ++fn) { \ switch (P.VU.vsew) { \ case e8: \ - MMU.store<uint8_t>(baseAddr + index[i] + fn * 1, \ + MMU.store<uint8_t>(baseAddr + index + fn * 1, \ P.VU.elt<uint8_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ case e16: \ - MMU.store<uint16_t>(baseAddr + index[i] + fn * 2, \ + MMU.store<uint16_t>(baseAddr + index + fn * 2, \ P.VU.elt<uint16_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ case e32: \ - MMU.store<uint32_t>(baseAddr + index[i] + fn * 4, \ + MMU.store<uint32_t>(baseAddr + index + fn * 4, \ P.VU.elt<uint32_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ default: \ - MMU.store<uint64_t>(baseAddr + index[i] + fn * 8, \ + MMU.store<uint64_t>(baseAddr + index + fn * 8, \ P.VU.elt<uint64_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ } \ @@ -1310,10 +1289,10 @@ reg_t index[P.VU.vlmax]; \ #define VI_LDST_FF(elt_width) \ const reg_t nf = insn.v_nf() + 1; \ + VI_CHECK_LOAD(elt_width, false); \ const reg_t vl = p->VU.vl->read(); \ const reg_t baseAddr = RS1; \ const reg_t rd_num = insn.rd(); \ - VI_CHECK_LOAD(elt_width, false); \ bool early_stop = false; \ for (reg_t i = p->VU.vstart->read(); i < vl; ++i) { \ VI_STRIP(i); \ @@ -1484,9 +1463,7 @@ reg_t index[P.VU.vlmax]; \ VI_VFP_COMMON \ for (reg_t i = P.VU.vstart->read(); i < vl; ++i) { \ VI_LOOP_ELEMENT_SKIP(); \ - uint64_t mmask = UINT64_C(1) << mpos; \ - uint64_t &vd = P.VU.elt<uint64_t>(rd_num, midx, true); \ - uint64_t res = 0; + bool res = false; #define VI_VFP_LOOP_REDUCTION_BASE(width) \ float##width##_t vd_0 = P.VU.elt<float##width##_t>(rd_num, 0); \ @@ -1564,7 +1541,7 @@ reg_t index[P.VU.vlmax]; \ case e16: \ case e32: \ case e64: { \ - vd = (vd & ~mmask) | (((res) << mpos) & mmask); \ + P.VU.set_mask_elt(insn.rd(), i, res); \ break; \ } \ default: \ diff --git a/riscv/vector_unit.cc b/riscv/vector_unit.cc index 08adc61..7c6633c 100644 --- a/riscv/vector_unit.cc +++ b/riscv/vector_unit.cc @@ -13,15 +13,15 @@ void vectorUnit_t::vectorUnit_t::reset() reg_file = malloc(NVPR * vlenb); memset(reg_file, 0, NVPR * vlenb); - auto& csrmap = p->get_state()->csrmap; - csrmap[CSR_VXSAT] = vxsat = std::make_shared<vxsat_csr_t>(p, CSR_VXSAT); - csrmap[CSR_VSTART] = vstart = std::make_shared<vector_csr_t>(p, CSR_VSTART, /*mask*/ VLEN - 1); - csrmap[CSR_VXRM] = vxrm = std::make_shared<vector_csr_t>(p, CSR_VXRM, /*mask*/ 0x3ul); - csrmap[CSR_VL] = vl = std::make_shared<vector_csr_t>(p, CSR_VL, /*mask*/ 0); - csrmap[CSR_VTYPE] = vtype = std::make_shared<vector_csr_t>(p, CSR_VTYPE, /*mask*/ 0); - csrmap[CSR_VLENB] = std::make_shared<vector_csr_t>(p, CSR_VLENB, /*mask*/ 0, /*init*/ vlenb); + auto state = p->get_state(); + state->add_csr(CSR_VXSAT, vxsat = std::make_shared<vxsat_csr_t>(p, CSR_VXSAT)); + state->add_csr(CSR_VSTART, vstart = std::make_shared<vector_csr_t>(p, CSR_VSTART, /*mask*/ VLEN - 1)); + state->add_csr(CSR_VXRM, vxrm = std::make_shared<vector_csr_t>(p, CSR_VXRM, /*mask*/ 0x3ul)); + state->add_csr(CSR_VL, vl = std::make_shared<vector_csr_t>(p, CSR_VL, /*mask*/ 0)); + state->add_csr(CSR_VTYPE, vtype = std::make_shared<vector_csr_t>(p, CSR_VTYPE, /*mask*/ 0)); + state->add_csr(CSR_VLENB, std::make_shared<vector_csr_t>(p, CSR_VLENB, /*mask*/ 0, /*init*/ vlenb)); assert(VCSR_VXSAT_SHIFT == 0); // composite_csr_t assumes vxsat begins at bit 0 - csrmap[CSR_VCSR] = std::make_shared<composite_csr_t>(p, CSR_VCSR, vxrm, vxsat, VCSR_VXRM_SHIFT); + state->add_csr(CSR_VCSR, std::make_shared<composite_csr_t>(p, CSR_VCSR, vxrm, vxsat, VCSR_VXRM_SHIFT)); vtype->write_raw(0); set_vl(0, 0, 0, -1); // default to illegal configuration @@ -29,10 +29,11 @@ void vectorUnit_t::vectorUnit_t::reset() reg_t vectorUnit_t::vectorUnit_t::set_vl(int rd, int rs1, reg_t reqVL, reg_t newType) { - int new_vlmul = 0; if (vtype->read() != newType) { + int new_vlmul = int8_t(extract64(newType, 0, 3) << 5) >> 5; + auto old_vlmax = vlmax; + vsew = 1 << (extract64(newType, 3, 3) + 3); - new_vlmul = int8_t(extract64(newType, 0, 3) << 5) >> 5; vflmul = new_vlmul >= 0 ? 1 << new_vlmul : 1.0 / (1 << -new_vlmul); vlmax = (VLEN/vsew) * vflmul; vta = extract64(newType, 6, 1); @@ -40,7 +41,8 @@ reg_t vectorUnit_t::vectorUnit_t::set_vl(int rd, int rs1, reg_t reqVL, reg_t new vill = !(vflmul >= 0.125 && vflmul <= 8) || vsew > std::min(vflmul, 1.0f) * ELEN - || (newType >> 8) != 0; + || (newType >> 8) != 0 + || (rd == 0 && rs1 == 0 && old_vlmax != vlmax); if (vill) { vlmax = 0; @@ -54,7 +56,7 @@ reg_t vectorUnit_t::vectorUnit_t::set_vl(int rd, int rs1, reg_t reqVL, reg_t new if (vlmax == 0) { vl->write_raw(0); } else if (rd == 0 && rs1 == 0) { - vl->write_raw(std::min(vl->read(), vlmax)); + ; // retain current VL } else if (rd != 0 && rs1 == 0) { vl->write_raw(vlmax); } else if (rs1 != 0) { diff --git a/riscv/vector_unit.h b/riscv/vector_unit.h index a057c62..0e80618 100644 --- a/riscv/vector_unit.h +++ b/riscv/vector_unit.h @@ -108,6 +108,17 @@ public: template<typename EG> EG& elt_group(reg_t vReg, reg_t n, bool is_write = false); + bool mask_elt(reg_t vReg, reg_t n) + { + return (elt<uint8_t>(vReg, n / 8) >> (n % 8)) & 1; + } + + void set_mask_elt(reg_t vReg, reg_t n, bool value) + { + auto& e = elt<uint8_t>(vReg, n / 8, true); + e = (e & ~(1U << (n % 8))) | (value << (n % 8)); + } + public: void reset(); diff --git a/riscv/zicfiss.h b/riscv/zicfiss.h index 83c166d..c7aef64 100644 --- a/riscv/zicfiss.h +++ b/riscv/zicfiss.h @@ -25,7 +25,7 @@ shadow_return_addr = MMU.ss_load<uint32_t>(STATE.ssp->read()); \ else \ shadow_return_addr = MMU.ss_load<uint64_t>(STATE.ssp->read()); \ - software_check(value == shadow_return_addr, SHADOW_STACK_FAULT); \ + software_check(zext_xlen(value) == shadow_return_addr, SHADOW_STACK_FAULT); \ STATE.ssp->write(STATE.ssp->read() + xlen / 8); #endif diff --git a/riscv/zvk_ext_macros.h b/riscv/zvk_ext_macros.h index f094629..702ad91 100644 --- a/riscv/zvk_ext_macros.h +++ b/riscv/zvk_ext_macros.h @@ -86,6 +86,32 @@ // (LMUL * VLEN) <= EGW #define require_egw_fits(EGW) require((EGW) <= (P.VU.VLEN * P.VU.vflmul)) +// Ensures that a register index is aligned to EMUL +// evaluated as EGW / VLEN. +// The check is only enabled if this value is greater +// than one (no index alignment check required for fractional EMUL) +#define require_vreg_align_eglmul(EGW, VREG_NUM) \ + do { \ + float vfeglmul = EGW / P.VU.VLEN; \ + if (vfeglmul > 1) { \ + require_align(VREG_NUM, vfeglmul); \ + }\ + } while (0) + +#define require_vs2_align_eglmul(EGW) require_vreg_align_eglmul(EGW, insn.rs2()) + +// ensure that rs2 and rd do not overlap, assuming rd encodes an LMUL wide +// vector register group and rs2 encodes an vs2_EMUL=ceil(EGW / VLEN) vector register +// group. +// Assumption: LMUL >= vs2_EMUL which is enforced independently through require_egw_fits. +#define require_noover_eglmul(vd, vs2) \ + do { \ + int vd_emul = P.VU.vflmul < 1.f ? 1 : (int) P.VU.vflmul; \ + int aligned_vd = vd / vd_emul; \ + int aligned_vs2 = vs2 / vd_emul; \ + require(aligned_vd != aligned_vs2); \ + } while (0) + // Checks that the vector unit state (vtype and vl) can be interpreted // as element groups with EEW=32, EGS=4 (four 32-bits elements per group), // for an effective element group width of EGW=128 bits. diff --git a/riscv/zvkned_ext_macros.h b/riscv/zvkned_ext_macros.h index db705c7..d94ddc2 100644 --- a/riscv/zvkned_ext_macros.h +++ b/riscv/zvkned_ext_macros.h @@ -2,6 +2,7 @@ // the RISC-V Zvkned extension (vector AES single round). #include "insns/aes_common.h" +#include "zvk_ext_macros.h" #ifndef RISCV_ZVKNED_EXT_MACROS_H_ #define RISCV_ZVKNED_EXT_MACROS_H_ @@ -9,16 +10,22 @@ // vaes*.vs instruction constraints: // - Zvkned is enabled // - EGW (128) <= LMUL * VLEN +// - vd is LMUL aligned +// - vs2 is ceil(EGW / VLEN) aligned // - vd and vs2 cannot overlap // // The constraint that vstart and vl are both EGS (4) aligned // is checked in the VI_ZVK_..._EGU32x4_..._LOOP macros. #define require_vaes_vs_constraints \ do { \ + const uint32_t EGS = 4; \ require_zvkned; \ + require(P.VU.vl->read() % EGS == 0); \ require(P.VU.vsew == 32); \ require_egw_fits(128); \ - require(insn.rd() != insn.rs2()); \ + require_align(insn.rd(), P.VU.vflmul); \ + require_vs2_align_eglmul(128); \ + require_noover_eglmul(insn.rd(), insn.rs2()); \ } while (false) // vaes*.vv instruction constraints. Those are the same as the .vs ones, @@ -30,17 +37,24 @@ // is checked in the VI_ZVK_..._EGU32x4_..._LOOP macros. #define require_vaes_vv_constraints \ do { \ + const uint32_t EGS = 4; \ require_zvkned; \ + require(P.VU.vl->read() % EGS == 0); \ require(P.VU.vsew == 32); \ require_egw_fits(128); \ + VI_CHECK_SSS(false) \ } while (false) // vaeskf*.vi instruction constraints. Those are the same as the .vv ones. #define require_vaeskf_vi_constraints \ do { \ + const uint32_t EGS = 4; \ require_zvkned; \ + require(P.VU.vstart->read() % EGS == 0); \ + require(P.VU.vl->read() % EGS == 0); \ require(P.VU.vsew == 32); \ require_egw_fits(128); \ + VI_CHECK_SSS(false) \ } while (false) #define VAES_XTIME(A) (((A) << 1) ^ (((A) & 0x80) ? 0x1b : 0)) diff --git a/riscv/zvknh_ext_macros.h b/riscv/zvknh_ext_macros.h index b50818b..98236b0 100644 --- a/riscv/zvknh_ext_macros.h +++ b/riscv/zvknh_ext_macros.h @@ -15,6 +15,7 @@ // macros. #define require_vsha2_common_constraints \ do { \ + VI_CHECK_SSS(true) \ require(P.VU.vsew == 32 || P.VU.vsew == 64); \ require(insn.rd() != insn.rs1()); \ require(insn.rd() != insn.rs2()); \ diff --git a/riscv/zvksed_ext_macros.h b/riscv/zvksed_ext_macros.h index 46e399b..3ffa272 100644 --- a/riscv/zvksed_ext_macros.h +++ b/riscv/zvksed_ext_macros.h @@ -16,9 +16,12 @@ // is checked in the VI_ZVK_..._EGU32x4_..._LOOP macros. #define require_vsm4_constraints \ do { \ + const uint32_t EGS = 4; \ require_zvksed; \ require(P.VU.vsew == 32); \ require_egw_fits(128); \ + require(P.VU.vstart->read() % EGS == 0); \ + require(P.VU.vl->read() % EGS == 0); \ } while (false) // Returns a uint32_t value constructed from the 4 bytes (uint8_t) diff --git a/riscv/zvksh_ext_macros.h b/riscv/zvksh_ext_macros.h index 71c5a09..c4549da 100644 --- a/riscv/zvksh_ext_macros.h +++ b/riscv/zvksh_ext_macros.h @@ -16,9 +16,12 @@ // is checked in the VI_ZVK_..._EGU32x8_..._LOOP macros. #define require_vsm3_constraints \ do { \ + const uint32_t EGS = 8; \ require_zvksh; \ require(P.VU.vsew == 32); \ require_egw_fits(256); \ + require(P.VU.vstart->read() % EGS == 0); \ + require(P.VU.vl->read() % EGS == 0); \ require(insn.rd() != insn.rs2()); \ } while (false) diff --git a/scripts/config.guess b/scripts/config.guess index 699b3a1..cdfc439 100644..100755 --- a/scripts/config.guess +++ b/scripts/config.guess @@ -1,12 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2020 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. -timestamp='2020-11-19' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2023-08-22' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -32,12 +34,20 @@ timestamp='2020-11-19' # Please send patches to <config-patches@gnu.org>. -me=$(echo "$0" | sed -e 's,.*/,,') +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] -Output the configuration name of the system \`$me' is run on. +Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit @@ -50,13 +60,13 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2020 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -84,13 +94,16 @@ if test $# != 0; then exit 1 fi +# Just in case it came from the environment. +GUESS= + # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. +# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still +# use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. @@ -102,8 +115,8 @@ set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039 - { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } || + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } @@ -112,7 +125,7 @@ set_cc_for_build() { ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$driver" + CC_FOR_BUILD=$driver break fi done @@ -131,17 +144,20 @@ if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi -UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown -UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown -UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown -UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "$UNAME_SYSTEM" in +case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else #include <features.h> #if defined(__UCLIBC__) LIBC=uclibc @@ -156,8 +172,10 @@ Linux|GNU|GNU/*) LIBC=musl #endif #endif + #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && @@ -176,7 +194,7 @@ esac # Note: order is significant - the case branches are not exclusive. -case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -188,12 +206,11 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ - "/sbin/$sysctl" 2>/dev/null || \ - "/usr/sbin/$sysctl" 2>/dev/null || \ - echo unknown)) - case "$UNAME_MACHINE_ARCH" in + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; @@ -201,15 +218,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,') - endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p') - machine="${arch}${endian}"-unknown + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown ;; - *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; @@ -230,10 +247,10 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in ;; esac # Determine ABI tags. - case "$UNAME_MACHINE_ARCH" in + case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr") + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -241,76 +258,82 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "$UNAME_VERSION" in + case $UNAME_VERSION in Debian*) release='-gnu' ;; *) - release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi-}" - exit ;; + GUESS=$machine-${os}${release}${abi-} + ;; *:Bitrig:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') - echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') - echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') - echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" - exit ;; + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; *:MidnightBSD:*:*) - echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; *:ekkoBSD:*:*) - echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; *:SolidBSD:*:*) - echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; *:OS108:*:*) - echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; *:MirBSD:*:*) - echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; *:Sortix:*:*) - echo "$UNAME_MACHINE"-unknown-sortix - exit ;; + GUESS=$UNAME_MACHINE-unknown-sortix + ;; *:Twizzler:*:*) - echo "$UNAME_MACHINE"-unknown-twizzler - exit ;; + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; *:Redox:*:*) - echo "$UNAME_MACHINE"-unknown-redox - exit ;; + GUESS=$UNAME_MACHINE-unknown-redox + ;; mips:OSF1:*.*) - echo mips-dec-osf1 - exit ;; + GUESS=mips-dec-osf1 + ;; alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 case $UNAME_RELEASE in *4.0) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) - case "$ALPHA_CPU_TYPE" in + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") @@ -347,68 +370,69 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; + GUESS=m68k-unknown-sysv4 + ;; *:[Aa]miga[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-amigaos - exit ;; + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; *:[Mm]orph[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-morphos - exit ;; + GUESS=$UNAME_MACHINE-unknown-morphos + ;; *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; + GUESS=i370-ibm-openedition + ;; *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; + GUESS=s390-ibm-zvmoe + ;; *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; + GUESS=powerpc-ibm-os400 + ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix"$UNAME_RELEASE" - exit ;; + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; + GUESS=arm-unknown-riscos + ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; + GUESS=hppa1.1-hitachi-hiuxmpp + ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "$( (/bin/universe) 2>/dev/null)" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; + GUESS=pyramid-pyramid-svr4 + ;; DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; + GUESS=sparc-icl-nx6 + ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case $(/usr/bin/uname -p) in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux"$UNAME_RELEASE" - exit ;; + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 @@ -417,47 +441,50 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi - echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; sun4*:SunOS:*:*) - case "$(/usr/bin/arch -k)" in + case `/usr/bin/arch -k` in Series*|S4*) - UNAME_RELEASE=$(uname -v) + UNAME_RELEASE=`uname -v` ;; esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" - exit ;; + # Japanese Language versions have a version number like '4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; sun*:*:4.2BSD:*) - UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "$(/bin/arch)" in + case `/bin/arch` in sun3) - echo m68k-sun-sunos"$UNAME_RELEASE" + GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) - echo sparc-sun-sunos"$UNAME_RELEASE" + GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac - exit ;; + ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -467,41 +494,41 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; m68k:machten:*:*) - echo m68k-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; powerpc:machten:*:*) - echo powerpc-apple-machten"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; + GUESS=mips-dec-mach_bsd4.3 + ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix"$UNAME_RELEASE" - exit ;; + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix"$UNAME_RELEASE" - exit ;; + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -526,78 +553,79 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') && - SYSTEM_NAME=$("$dummy" "$dummyarg") && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos"$UNAME_RELEASE" - exit ;; + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; + GUESS=powerpc-motorola-powermax + ;; Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; + GUESS=powerpc-harris-powerunix + ;; m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; + GUESS=m88k-harris-cxux7 + ;; m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; + GUESS=m88k-motorola-sysv4 + ;; m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=$(/usr/bin/uname -p) + UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux"$UNAME_RELEASE" + GUESS=m88k-dg-dgux$UNAME_RELEASE else - echo m88k-dg-dguxbcs"$UNAME_RELEASE" + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else - echo i586-dg-dgux"$UNAME_RELEASE" + GUESS=i586-dg-dgux$UNAME_RELEASE fi - exit ;; + ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; + GUESS=m88k-dolphin-sysv3 + ;; M88*:*:R3*:*) # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; + GUESS=m88k-tektronix-sysv3 + ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; + GUESS=m68k-tektronix-bsd + ;; *:IRIX*:*:*) - echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" - exit ;; + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; + GUESS=i386-ibm-aix + ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then - IBM_REV=$(/usr/bin/oslevel) + IBM_REV=`/usr/bin/oslevel` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build @@ -612,68 +640,68 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then - echo "$SYSTEM_NAME" + GUESS=$SYSTEM_NAME else - echo rs6000-ibm-aix3.2.5 + GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 + GUESS=rs6000-ibm-aix3.2.4 else - echo rs6000-ibm-aix3.2 + GUESS=rs6000-ibm-aix3.2 fi - exit ;; + ;; *:AIX:*:[4567]) - IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }') + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then - IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/) + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo "$IBM_ARCH"-ibm-aix"$IBM_REV" - exit ;; + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; + GUESS=rs6000-ibm-aix + ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - echo romp-ibm-bsd4.4 - exit ;; + GUESS=romp-ibm-bsd4.4 + ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; + GUESS=rs6000-bull-bosx + ;; DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; + GUESS=m68k-bull-sysv3 + ;; 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; + GUESS=m68k-hp-bsd + ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; + GUESS=m68k-hp-bsd4.4 + ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - case "$UNAME_MACHINE" in + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then - sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null) - sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null) - case "$sc_cpu_version" in + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "$sc_kernel_bits" in + case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 @@ -715,7 +743,7 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy") + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac @@ -740,12 +768,12 @@ EOF HP_ARCH=hppa64 fi fi - echo "$HP_ARCH"-hp-hpux"$HPUX_REV" - exit ;; + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; ia64:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - echo ia64-hp-hpux"$HPUX_REV" - exit ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" @@ -773,38 +801,38 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; + GUESS=unknown-hitachi-hiuxwe2 + ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - echo hppa1.1-hp-bsd - exit ;; + GUESS=hppa1.1-hp-bsd + ;; 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; + GUESS=hppa1.0-hp-bsd + ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; + GUESS=hppa1.0-hp-mpeix + ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - echo hppa1.1-hp-osf - exit ;; + GUESS=hppa1.1-hp-osf + ;; hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; + GUESS=hppa1.0-hp-osf + ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then - echo "$UNAME_MACHINE"-unknown-osf1mk + GUESS=$UNAME_MACHINE-unknown-osf1mk else - echo "$UNAME_MACHINE"-unknown-osf1 + GUESS=$UNAME_MACHINE-unknown-osf1 fi - exit ;; + ;; parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; + GUESS=hppa1.1-hp-lites + ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; + GUESS=c1-convex-bsd + ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd @@ -812,17 +840,18 @@ EOF fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; + GUESS=c34-convex-bsd + ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; + GUESS=c38-convex-bsd + ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; + GUESS=c4-convex-bsd + ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ @@ -830,114 +859,155 @@ EOF -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; *:BSD/OS:*:*) - echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; arm:FreeBSD:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi - exit ;; + ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=$(/usr/bin/uname -p) - case "$UNAME_PROCESSOR" in + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; i*:CYGWIN*:*) - echo "$UNAME_MACHINE"-pc-cygwin - exit ;; + GUESS=$UNAME_MACHINE-pc-cygwin + ;; *:MINGW64*:*) - echo "$UNAME_MACHINE"-pc-mingw64 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; *:MINGW*:*) - echo "$UNAME_MACHINE"-pc-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; *:MSYS*:*) - echo "$UNAME_MACHINE"-pc-msys - exit ;; + GUESS=$UNAME_MACHINE-pc-msys + ;; i*:PW*:*) - echo "$UNAME_MACHINE"-pc-pw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) - case "$UNAME_MACHINE" in + case $UNAME_MACHINE in x86) - echo i586-pc-interix"$UNAME_RELEASE" - exit ;; + GUESS=i586-pc-interix$UNAME_RELEASE + ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; IA64) - echo ia64-unknown-interix"$UNAME_RELEASE" - exit ;; + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; esac ;; i*:UWIN*:*) - echo "$UNAME_MACHINE"-pc-uwin - exit ;; + GUESS=$UNAME_MACHINE-pc-uwin + ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-pc-cygwin - exit ;; + GUESS=x86_64-pc-cygwin + ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; *:GNU:*:*) # the GNU system - echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" - exit ;; + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" - exit ;; + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) - echo "$UNAME_MACHINE"-unknown-minix - exit ;; + GUESS=$UNAME_MACHINE-unknown-minix + ;; aarch64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __ARM_EABI__ + #ifdef __ARM_PCS_VFP + ABI=eabihf + #else + ABI=eabi + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; + esac + fi + GUESS=$CPU-unknown-linux-$LIBCABI + ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; alpha:Linux:*:*) - case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -948,60 +1018,72 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi - exit ;; + ;; avr32*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; cris:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; crisv32:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; e2k:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; frv:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; hexagon:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; ia64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:cos:*:*) + GUESS=$UNAME_MACHINE-unknown-cos + ;; + kvx:mbr:*:*) + GUESS=$UNAME_MACHINE-unknown-mbr + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m68*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 @@ -1046,138 +1128,150 @@ EOF #endif #endif EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" - exit ;; + GUESS=or1k-unknown-linux-$LIBC + ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; padre:Linux:*:*) - echo sparc-unknown-linux-"$LIBC" - exit ;; + GUESS=sparc-unknown-linux-$LIBC + ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-"$LIBC" - exit ;; + GUESS=hppa64-unknown-linux-$LIBC + ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level - case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in - PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; - PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; - *) echo hppa-unknown-linux-"$LIBC" ;; + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; esac - exit ;; + ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64-unknown-linux-$LIBC + ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc-unknown-linux-$LIBC + ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpc64le-unknown-linux-$LIBC + ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-"$LIBC" - exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; s390:Linux:*:* | s390x:Linux:*:*) - echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; sh64*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sh*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; vax:Linux:*:*) - echo "$UNAME_MACHINE"-dec-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; x86_64:Linux:*:*) set_cc_for_build + CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI="$LIBC"x32 - fi + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac fi - echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" - exit ;; + GUESS=$CPU-pc-linux-$LIBCABI + ;; xtensa*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; + GUESS=i386-sequent-sysv4 + ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" - exit ;; + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility + # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. - echo "$UNAME_MACHINE"-pc-os2-emx - exit ;; + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; i*86:XTS-300:*:STOP) - echo "$UNAME_MACHINE"-unknown-stop - exit ;; + GUESS=$UNAME_MACHINE-unknown-stop + ;; i*86:atheos:*:*) - echo "$UNAME_MACHINE"-unknown-atheos - exit ;; + GUESS=$UNAME_MACHINE-unknown-atheos + ;; i*86:syllable:*:*) - echo "$UNAME_MACHINE"-pc-syllable - exit ;; + GUESS=$UNAME_MACHINE-pc-syllable + ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; i*86:*DOS:*:*) - echo "$UNAME_MACHINE"-pc-msdosdjgpp - exit ;; + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; i*86:*:4.*:*) - UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi - exit ;; + ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. - case $(/bin/uname -X | grep "^Machine") in + case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" - exit ;; + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then - UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name) - echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL" + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL elif /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 @@ -1185,11 +1279,11 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else - echo "$UNAME_MACHINE"-pc-sysv32 + GUESS=$UNAME_MACHINE-pc-sysv32 fi - exit ;; + ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about @@ -1197,37 +1291,37 @@ EOF # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; + GUESS=i586-pc-msdosdjgpp + ;; Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; + GUESS=i386-pc-mach3 + ;; paragon:*:*:*) - echo i860-intel-osf1 - exit ;; + GUESS=i860-intel-osf1 + ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi - exit ;; + ;; mini*:CTIX:SYS*5:*) # "miniframe" - echo m68010-convergent-sysv - exit ;; + GUESS=m68010-convergent-sysv + ;; mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; + GUESS=m68k-convergent-sysv + ;; M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; + GUESS=m68k-diab-dnix + ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1238,7 +1332,7 @@ EOF NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ @@ -1246,118 +1340,121 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; + GUESS=m68k-atari-sysv4 + ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv"$UNAME_RELEASE" - exit ;; + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - echo "$UNAME_MACHINE"-sni-sysv4 + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 else - echo ns32k-sni-sysv + GUESS=ns32k-sni-sysv fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + ;; + PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says <Richard.M.Bartel@ccMail.Census.GOV> - echo i586-unisys-sysv4 - exit ;; + GUESS=i586-unisys-sysv4 + ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes <hewes@openmarket.com>. # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; + GUESS=hppa1.1-stratus-sysv4 + ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; + GUESS=i860-stratus-sysv4 + ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo "$UNAME_MACHINE"-stratus-vos - exit ;; + GUESS=$UNAME_MACHINE-stratus-vos + ;; *:VOS:*:*) # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; + GUESS=hppa1.1-stratus-vos + ;; mc68*:A/UX:*:*) - echo m68k-apple-aux"$UNAME_RELEASE" - exit ;; + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; + GUESS=mips-sony-newsos6 + ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then - echo mips-nec-sysv"$UNAME_RELEASE" + GUESS=mips-nec-sysv$UNAME_RELEASE else - echo mips-unknown-sysv"$UNAME_RELEASE" + GUESS=mips-unknown-sysv$UNAME_RELEASE fi - exit ;; + ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; + GUESS=powerpc-be-beos + ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; + GUESS=powerpc-apple-beos + ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; + GUESS=i586-pc-beos + ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux"$UNAME_RELEASE" - exit ;; + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; *:Rhapsody:*:*) - echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; arm64:Darwin:*:*) - echo aarch64-apple-darwin"$UNAME_RELEASE" - exit ;; + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; *:Darwin:*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac @@ -1391,109 +1488,119 @@ EOF # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi - echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=$(uname -p) + UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; *:QNX:*:4*) - echo i386-pc-qnx - exit ;; + GUESS=i386-pc-qnx + ;; NEO-*:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; NSR-*:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; NSV-*:NONSTOP_KERNEL:*:*) - echo nsv-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; NSX-*:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk"$UNAME_RELEASE" - exit ;; + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; + GUESS=mips-compaq-nonstopux + ;; BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; + GUESS=bs2000-siemens-sysv + ;; DS/*:UNIX_System_V:*:*) - echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - # shellcheck disable=SC2154 - if test "$cputype" = 386; then + if test "${cputype-}" = 386; then UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype fi - echo "$UNAME_MACHINE"-unknown-plan9 - exit ;; + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; + GUESS=pdp10-unknown-tops10 + ;; *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; + GUESS=pdp10-unknown-tenex + ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; + GUESS=pdp10-dec-tops20 + ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; + GUESS=pdp10-xkl-tops20 + ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; + GUESS=pdp10-unknown-tops20 + ;; *:ITS:*:*) - echo pdp10-unknown-its - exit ;; + GUESS=pdp10-unknown-its + ;; SEI:*:*:SEIUX) - echo mips-sei-seiux"$UNAME_RELEASE" - exit ;; + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; *:*VMS:*:*) - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - case "$UNAME_MACHINE" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; + GUESS=i386-pc-xenix + ;; i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" - exit ;; + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; i*86:rdos:*:*) - echo "$UNAME_MACHINE"-pc-rdos - exit ;; - i*86:AROS:*:*) - echo "$UNAME_MACHINE"-pc-aros - exit ;; + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; x86_64:VMkernel:*:*) - echo "$UNAME_MACHINE"-unknown-esx - exit ;; + GUESS=$UNAME_MACHINE-unknown-esx + ;; amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; + GUESS=x86_64-unknown-onefs + ;; *:Unleashed:*:*) - echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" - exit ;; + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; esac +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" <<EOF @@ -1533,7 +1640,7 @@ main () #define __ARCHITECTURE__ "m68k" #endif int version; - version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null); + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else @@ -1625,7 +1732,7 @@ main () } EOF -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) && +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. @@ -1633,7 +1740,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 -case "$UNAME_MACHINE:$UNAME_SYSTEM" in +case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <<EOF @@ -1655,9 +1762,11 @@ and https://git.savannah.gnu.org/cgit/config.git/plain/config.sub EOF -year=$(echo $timestamp | sed 's,-.*,,') +our_year=`echo $timestamp | sed 's,-.*,,'` +thisyear=`date +%Y` # shellcheck disable=SC2003 -if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then +script_age=`expr "$thisyear" - "$our_year"` +if test "$script_age" -lt 3 ; then cat >&2 <<EOF If $0 has already been updated, send the following data and any @@ -1666,20 +1775,20 @@ provide the necessary information to handle your system. config.guess timestamp = $timestamp -uname -m = $( (uname -m) 2>/dev/null || echo unknown) -uname -r = $( (uname -r) 2>/dev/null || echo unknown) -uname -s = $( (uname -s) 2>/dev/null || echo unknown) -uname -v = $( (uname -v) 2>/dev/null || echo unknown) +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` -/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null) -/bin/uname -X = $( (/bin/uname -X) 2>/dev/null) +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` -hostinfo = $( (hostinfo) 2>/dev/null) -/bin/universe = $( (/bin/universe) 2>/dev/null) -/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null) -/bin/arch = $( (/bin/arch) 2>/dev/null) -/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null) -/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null) +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" diff --git a/scripts/config.sub b/scripts/config.sub index 19c9553..defe52c 100644..100755 --- a/scripts/config.sub +++ b/scripts/config.sub @@ -1,12 +1,14 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2020 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. -timestamp='2020-12-02' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2023-09-19' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -50,7 +52,14 @@ timestamp='2020-12-02' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. -me=$(echo "$0" | sed -e 's,.*/,,') +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS @@ -67,13 +76,13 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright 1992-2020 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -112,14 +121,16 @@ esac # Split fields of configuration type # shellcheck disable=SC2162 +saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <<EOF $1 EOF +IFS=$saved_IFS # Separate into logical components for further validation case $1 in *-*-*-*-*) - echo Invalid configuration \`"$1"\': more than four components >&2 + echo "Invalid configuration '$1': more than four components" >&2 exit 1 ;; *-*-*-*) @@ -134,7 +145,8 @@ case $1 in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) + | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ + | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; @@ -163,6 +175,10 @@ case $1 in basic_machine=$field1 basic_os=$field2 ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ @@ -769,22 +785,22 @@ case $basic_machine in vendor=hp ;; i*86v32) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) - cpu=$(echo "$1" | sed -e 's/86.*/86/') + cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; @@ -917,16 +933,18 @@ case $basic_machine in ;; leon-*|leon[3-9]-*) cpu=sparc - vendor=$(echo "$basic_machine" | sed 's/-.*//') + vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 + saved_IFS=$IFS IFS="-" read cpu vendor <<EOF $basic_machine EOF + IFS=$saved_IFS ;; - # We use `pc' rather than `unknown' + # We use 'pc' rather than 'unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) @@ -1003,6 +1021,11 @@ case $cpu-$vendor in ;; # Here we normalize CPU types with a missing or matching vendor + armh-unknown | armh-alt) + cpu=armv7l + vendor=alt + basic_os=${basic_os:-linux-gnueabihf} + ;; dpx20-unknown | dpx20-bull) cpu=rs6000 vendor=bull @@ -1053,7 +1076,7 @@ case $cpu-$vendor in pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) cpu=i586 ;; - pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*) cpu=i686 ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) @@ -1084,7 +1107,7 @@ case $cpu-$vendor in cpu=mipsisa64sb1el ;; sh5e[lb]-*) - cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/') + cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` ;; spur-*) cpu=spur @@ -1102,9 +1125,9 @@ case $cpu-$vendor in cpu=x86_64 ;; xscale-* | xscalee[bl]-*) - cpu=$(echo "$cpu" | sed 's/^xscale/arm/') + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` ;; - arm64-*) + arm64-* | aarch64le-*) cpu=aarch64 ;; @@ -1158,14 +1181,14 @@ case $cpu-$vendor in case $cpu in 1750a | 580 \ | a29k \ - | aarch64 | aarch64_be \ + | aarch64 | aarch64_be | aarch64c | arm64ec \ | abacus \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ | alphapca5[67] | alpha64pca5[67] \ | am33_2.0 \ | amdgcn \ - | arc | arceb \ + | arc | arceb | arc32 | arc64 \ | arm | arm[lb]e | arme[lb] | armv* \ | avr | avr32 \ | asmjs \ @@ -1177,40 +1200,23 @@ case $cpu-$vendor in | d10v | d30v | dlx | dsp16xx \ | e2k | elxsi | epiphany \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | javascript \ | h8300 | h8500 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i*86 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ + | kvx \ | le32 | le64 \ | lm32 \ + | loongarch32 | loongarch64 \ | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ | m88110 | m88k | maxq | mb | mcore | mep | metag \ | microblaze | microblazeel \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64eb | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ + | mips* \ | mmix \ | mn10200 | mn10300 \ | moxie \ @@ -1229,7 +1235,7 @@ case $cpu-$vendor in | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ | pru \ | pyramid \ - | riscv | riscv32 | riscv64 \ + | riscv | riscv32 | riscv32be | riscv64 | riscv64be \ | rl78 | romp | rs6000 | rx \ | s390 | s390x \ | score \ @@ -1258,7 +1264,7 @@ case $cpu-$vendor in ;; *) - echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2 exit 1 ;; esac @@ -1279,38 +1285,45 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if test x$basic_os != x +if test x"$basic_os" != x then -# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. +obj= case $basic_os in gnu/linux*) kernel=linux - os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 - os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto - os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 + saved_IFS=$IFS IFS="-" read kernel os <<EOF $basic_os EOF + IFS=$saved_IFS ;; # Default OS when just kernel was specified nto*) kernel=nto - os=$(echo $basic_os | sed -e 's|nto|qnx|') + os=`echo "$basic_os" | sed -e 's|nto|qnx|'` ;; linux*) kernel=linux - os=$(echo $basic_os | sed -e 's|linux|gnu|') + os=`echo "$basic_os" | sed -e 's|linux|gnu|'` + ;; + managarm*) + kernel=managarm + os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'` ;; *) kernel= @@ -1331,7 +1344,7 @@ case $os in os=cnk ;; solaris1 | solaris1.*) - os=$(echo $os | sed -e 's|solaris1|sunos4|') + os=`echo "$os" | sed -e 's|solaris1|sunos4|'` ;; solaris) os=solaris2 @@ -1360,7 +1373,7 @@ case $os in os=sco3.2v4 ;; sco3.2.[4-9]*) - os=$(echo $os | sed -e 's/sco3.2./sco3.2v/') + os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'` ;; sco*v* | scout) # Don't match below @@ -1390,7 +1403,7 @@ case $os in os=lynxos ;; mac[0-9]*) - os=$(echo "$os" | sed -e 's|mac|macos|') + os=`echo "$os" | sed -e 's|mac|macos|'` ;; opened*) os=openedition @@ -1399,10 +1412,10 @@ case $os in os=os400 ;; sunos5*) - os=$(echo "$os" | sed -e 's|sunos5|solaris2|') + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; sunos6*) - os=$(echo "$os" | sed -e 's|sunos6|solaris3|') + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; wince*) os=wince @@ -1436,7 +1449,7 @@ case $os in ;; # Preserve the version number of sinix5. sinix5.*) - os=$(echo $os | sed -e 's|sinix|sysv|') + os=`echo "$os" | sed -e 's|sinix|sysv|'` ;; sinix*) os=sysv4 @@ -1477,10 +1490,16 @@ case $os in os=eabi ;; *) - os=elf + os= + obj=elf ;; esac ;; + aout* | coff* | elf* | pe*) + # These are machine code file formats, not OSes + obj=$os + os= + ;; *) # No normalization, but not necessarily accepted, that comes below. ;; @@ -1499,12 +1518,15 @@ else # system, and we'll never get to this point. kernel= +obj= case $cpu-$vendor in score-*) - os=elf + os= + obj=elf ;; spu-*) - os=elf + os= + obj=elf ;; *-acorn) os=riscix1.2 @@ -1514,28 +1536,35 @@ case $cpu-$vendor in os=gnu ;; arm*-semi) - os=aout + os= + obj=aout ;; c4x-* | tic4x-*) - os=coff + os= + obj=coff ;; c8051-*) - os=elf + os= + obj=elf ;; clipper-intergraph) os=clix ;; hexagon-*) - os=elf + os= + obj=elf ;; tic54x-*) - os=coff + os= + obj=coff ;; tic55x-*) - os=coff + os= + obj=coff ;; tic6x-*) - os=coff + os= + obj=coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1557,19 +1586,24 @@ case $cpu-$vendor in os=sunos3 ;; m68*-cisco) - os=aout + os= + obj=aout ;; mep-*) - os=elf + os= + obj=elf ;; mips*-cisco) - os=elf + os= + obj=elf ;; mips*-*) - os=elf + os= + obj=elf ;; or32-*) - os=coff + os= + obj=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 @@ -1578,7 +1612,8 @@ case $cpu-$vendor in os=sunos4.1.1 ;; pru-*) - os=elf + os= + obj=elf ;; *-be) os=beos @@ -1659,10 +1694,12 @@ case $cpu-$vendor in os=uxpv ;; *-rom68k) - os=coff + os= + obj=coff ;; *-*bug) - os=coff + os= + obj=coff ;; *-apple) os=macos @@ -1680,13 +1717,20 @@ esac fi -# Now, validate our (potentially fixed-up) OS. +# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ). + case $os in - # Sometimes we do "kernel-abi", so those need to count as OSes. - musl* | newlib* | uclibc*) + # Sometimes we do "kernel-libc", so those need to count as OSes. + musl* | newlib* | relibc* | uclibc*) + ;; + # Likewise for "kernel-abi" + eabi* | gnueabi*) + ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) ;; - # Likewise for "kernel-libc" - eabi | eabihf | gnueabi | gnueabihf) + # See `case $cpu-$os` validation below + ghcjs) ;; # Now accept the basic system types. # The portable systems comes first. @@ -1696,20 +1740,20 @@ case $os in | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | hiux* | abug | nacl* | netware* | windows* \ - | os9* | macos* | osx* | ios* \ + | os9* | macos* | osx* | ios* | tvos* | watchos* \ | mpw* | magic* | mmixware* | mon960* | lnews* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ | mirbsd* | netbsd* | dicos* | openedition* | ose* \ - | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ - | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | bosx* | nextstep* | cxux* | oabi* \ + | ptx* | ecoff* | winnt* | domain* | vsta* \ | udi* | lites* | ieee* | go32* | aux* | hcos* \ - | chorusrdb* | cegcc* | glidix* \ - | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ + | cygwin* | msys* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | mint* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ @@ -1721,7 +1765,8 @@ case $os in | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*) + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* | mlibc* | cos* | mbr* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) @@ -1729,38 +1774,99 @@ case $os in ;; none) ;; + kernel* | msvc* ) + # Restricted further below + ;; + '') + if test x"$obj" = x + then + echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2 + fi + ;; + *) + echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 + exit 1 + ;; +esac + +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; *) - echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) +case $kernel-$os-$obj in + linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \ + | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- ) + ;; + uclinux-uclibc*- ) ;; - uclinux-uclibc* ) + managarm-mlibc*- | managarm-kernel*- ) ;; - -dietlibc* | -newlib* | -musl* | -uclibc* ) + windows*-msvc*-) + ;; + -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. - echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) + -kernel*- ) + echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 + exit 1 ;; - nto-qnx*) + *-kernel*- ) + echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 + exit 1 ;; - os2-emx) + *-msvc*- ) + echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 + exit 1 + ;; + kfreebsd*-gnu*- | kopensolaris*-gnu*-) + ;; + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) + ;; + nto-qnx*-) + ;; + os2-emx-) ;; - *-eabi* | *-gnueabi*) + *-eabi*- | *-gnueabi*-) ;; - -*) + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format + ;; + -*-) # Blank kernel with real OS is always fine. ;; - *-*) - echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) + echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac @@ -1843,7 +1949,7 @@ case $vendor in ;; esac -echo "$cpu-$vendor-${kernel:+$kernel-}$os" +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: diff --git a/scripts/install-sh b/scripts/install-sh new file mode 100755 index 0000000..7c56c9c --- /dev/null +++ b/scripts/install-sh @@ -0,0 +1,541 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2023-11-23.18; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Report bugs to <bug-automake@gnu.org>. +GNU Automake home page: <https://www.gnu.org/software/automake/>. +General help using GNU software: <https://www.gnu.org/gethelp/>." + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -p) cpprog="$cpprog -p";; + + -s) stripcmd=$stripprog;; + + -S) backupsuffix="$2" + shift;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/scripts/install.sh b/scripts/install.sh deleted file mode 100755 index 89fc9b0..0000000 --- a/scripts/install.sh +++ /dev/null @@ -1,238 +0,0 @@ -#! /bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. -# - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -tranformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/softfloat/bf16_classify.c b/softfloat/bf16_classify.c new file mode 100644 index 0000000..d1c6428 --- /dev/null +++ b/softfloat/bf16_classify.c @@ -0,0 +1,36 @@ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +uint_fast16_t bf16_classify( bfloat16_t a ) +{ + union ui16_f16 uA; + uint_fast16_t uiA; + + uA.f = a; + uiA = uA.ui; + + uint_fast16_t infOrNaN = expBF16UI( uiA ) == 0xFF; + uint_fast16_t subnormalOrZero = expBF16UI( uiA ) == 0; + bool sign = signBF16UI( uiA ); + bool fracZero = fracBF16UI( uiA ) == 0; + bool isNaN = isNaNBF16UI( uiA ); + bool isSNaN = softfloat_isSigNaNBF16UI( uiA ); + + return + ( sign && infOrNaN && fracZero ) << 0 | + ( sign && !infOrNaN && !subnormalOrZero ) << 1 | + ( sign && subnormalOrZero && !fracZero ) << 2 | + ( sign && subnormalOrZero && fracZero ) << 3 | + ( !sign && infOrNaN && fracZero ) << 7 | + ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | + ( !sign && subnormalOrZero && !fracZero ) << 5 | + ( !sign && subnormalOrZero && fracZero ) << 4 | + ( isNaN && isSNaN ) << 8 | + ( isNaN && !isSNaN ) << 9; +} + diff --git a/softfloat/bf16_cmp.c b/softfloat/bf16_cmp.c new file mode 100644 index 0000000..25daeef --- /dev/null +++ b/softfloat/bf16_cmp.c @@ -0,0 +1,65 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +bool bf16_eq( bfloat16_t a, bfloat16_t b ) +{ + float32_t f32A = { (uint_fast32_t)a.v << 16 }; + float32_t f32B = { (uint_fast32_t)b.v << 16 }; + + return f32_eq ( f32A, f32B ); +} + +bool bf16_le( bfloat16_t a, bfloat16_t b ) +{ + float32_t f32A = { (uint_fast32_t)a.v << 16 }; + float32_t f32B = { (uint_fast32_t)b.v << 16 }; + + return f32_le ( f32A, f32B ); +} + +bool bf16_lt( bfloat16_t a, bfloat16_t b ) +{ + float32_t f32A = { (uint_fast32_t)a.v << 16 }; + float32_t f32B = { (uint_fast32_t)b.v << 16 }; + + return f32_lt ( f32A, f32B ); +} diff --git a/softfloat/bf16_to_i32.c b/softfloat/bf16_to_i32.c new file mode 100644 index 0000000..86e4b37 --- /dev/null +++ b/softfloat/bf16_to_i32.c @@ -0,0 +1,48 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +int_fast32_t bf16_to_i32( bfloat16_t a, uint_fast8_t roundingMode, bool exact ) +{ + return f32_to_i32(bf16_to_f32(a), roundingMode, exact); +} + diff --git a/softfloat/bf16_to_i8.c b/softfloat/bf16_to_i8.c new file mode 100644 index 0000000..21b6f28 --- /dev/null +++ b/softfloat/bf16_to_i8.c @@ -0,0 +1,57 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdint.h> +#include "specialize.h" +#include "softfloat.h" + +int_fast8_t bf16_to_i8( bfloat16_t a, uint_fast8_t roundingMode, bool exact ) +{ + uint_fast8_t old_flags = softfloat_exceptionFlags; + + int_fast32_t sig32 = bf16_to_i32(a, roundingMode, exact); + + if (sig32 > INT8_MAX) { + softfloat_exceptionFlags = old_flags | softfloat_flag_invalid; + return i8_fromPosOverflow; + } else if (sig32 < INT8_MIN) { + softfloat_exceptionFlags = old_flags | softfloat_flag_invalid; + return i8_fromNegOverflow; + } else { + return sig32; + } +} + diff --git a/softfloat/bf16_to_ui32.c b/softfloat/bf16_to_ui32.c new file mode 100644 index 0000000..284bc7f --- /dev/null +++ b/softfloat/bf16_to_ui32.c @@ -0,0 +1,48 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +uint_fast32_t bf16_to_ui32( float16_t a, uint_fast8_t roundingMode, bool exact ) +{ + return f32_to_ui32(bf16_to_f32(a), roundingMode, exact); +} + diff --git a/softfloat/bf16_to_ui8.c b/softfloat/bf16_to_ui8.c new file mode 100644 index 0000000..a05c53f --- /dev/null +++ b/softfloat/bf16_to_ui8.c @@ -0,0 +1,54 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdint.h> +#include "specialize.h" +#include "softfloat.h" + +uint_fast8_t bf16_to_ui8( bfloat16_t a, uint_fast8_t roundingMode, bool exact ) +{ + uint_fast8_t old_flags = softfloat_exceptionFlags; + + uint_fast32_t sig32 = bf16_to_ui32(a, roundingMode, exact); + + if (sig32 > UINT8_MAX) { + softfloat_exceptionFlags = old_flags | softfloat_flag_invalid; + return ui8_fromPosOverflow; + } else { + return sig32; + } +} + diff --git a/softfloat/f128_classify.c b/softfloat/f128_classify.c index 1092a9b..1092a9b 100755..100644 --- a/softfloat/f128_classify.c +++ b/softfloat/f128_classify.c diff --git a/softfloat/f16_classify.c b/softfloat/f16_classify.c index 9402ff1..9402ff1 100755..100644 --- a/softfloat/f16_classify.c +++ b/softfloat/f16_classify.c diff --git a/softfloat/f32_classify.c b/softfloat/f32_classify.c index 83fad87..83fad87 100755..100644 --- a/softfloat/f32_classify.c +++ b/softfloat/f32_classify.c diff --git a/softfloat/f64_classify.c b/softfloat/f64_classify.c index 180abde..180abde 100755..100644 --- a/softfloat/f64_classify.c +++ b/softfloat/f64_classify.c diff --git a/softfloat/f64_to_bf16.c b/softfloat/f64_to_bf16.c index a320979..73ecf0e 100644 --- a/softfloat/f64_to_bf16.c +++ b/softfloat/f64_to_bf16.c @@ -43,12 +43,44 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bfloat16_t f64_to_bf16( float64_t a ) { - uint_fast8_t roundingMode = softfloat_roundingMode; - softfloat_roundingMode = softfloat_round_odd; + union ui64_f64 uA; + uint_fast64_t uiA; + bool sign; + int_fast16_t exp; + uint_fast64_t frac; + struct commonNaN commonNaN; + uint_fast16_t uiZ, frac16; + union ui16_f16 uZ; - float32_t f32A = f64_to_f32( a ); - - softfloat_roundingMode = roundingMode; - - return f32_to_bf16( f32A ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + uA.f = a; + uiA = uA.ui; + sign = signF64UI( uiA ); + exp = expF64UI( uiA ); + frac = fracF64UI( uiA ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + if ( exp == 0x7FF ) { + if ( frac ) { + softfloat_f64UIToCommonNaN( uiA, &commonNaN ); + uiZ = softfloat_commonNaNToBF16UI( &commonNaN ); + } else { + uiZ = packToBF16UI( sign, 0xFF, 0 ); + } + goto uiZ; + } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + frac16 = softfloat_shortShiftRightJam64( frac, 38 ); + if ( ! (exp | frac16) ) { + uiZ = packToBF16UI( sign, 0, 0 ); + goto uiZ; + } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + return softfloat_roundPackToBF16( sign, exp - 0x381, frac16 | 0x4000 ); + uiZ: + uZ.ui = uiZ; + return uZ.f; } diff --git a/softfloat/fall_maxmin.c b/softfloat/fall_maxmin.c index 32a9ade..f1efa87 100644 --- a/softfloat/fall_maxmin.c +++ b/softfloat/fall_maxmin.c @@ -72,10 +72,26 @@ float ## bits ## _t f ## bits ## _min( float ## bits ## _t a, float ## bits ## _ } \ } -COMPARE_MAX(a, b, 16); -COMPARE_MAX(a, b, 32); -COMPARE_MAX(a, b, 64); +COMPARE_MAX(a, b, 16) +COMPARE_MAX(a, b, 32) +COMPARE_MAX(a, b, 64) -COMPARE_MIN(a, b, 16); -COMPARE_MIN(a, b, 32); -COMPARE_MIN(a, b, 64); +COMPARE_MIN(a, b, 16) +COMPARE_MIN(a, b, 32) +COMPARE_MIN(a, b, 64) + +bfloat16_t bf16_max( bfloat16_t a, bfloat16_t b ) +{ + float32_t f32A = { (uint32_t)a.v << 16 }; + float32_t f32B = { (uint32_t)b.v << 16 }; + + return f32_to_bf16 ( f32_max( f32A, f32B ) ); +} + +bfloat16_t bf16_min( bfloat16_t a, bfloat16_t b ) +{ + float32_t f32A = { (uint32_t)a.v << 16 }; + float32_t f32B = { (uint32_t)b.v << 16 }; + + return f32_to_bf16 ( f32_min( f32A, f32B ) ); +} diff --git a/softfloat/fall_reciprocal.c b/softfloat/fall_reciprocal.c index 1c96458..622be1c 100644 --- a/softfloat/fall_reciprocal.c +++ b/softfloat/fall_reciprocal.c @@ -93,6 +93,43 @@ static inline uint64_t rsqrte7(uint64_t val, int e, int s, bool sub) { return (sign << (s+e)) | (out_exp << s) | out_sig; } +bfloat16_t bf16_rsqrte7(bfloat16_t in) +{ + union ui16_bf16 uA; + + uA.f = in; + unsigned int ret = bf16_classify(in); + bool sub = false; + switch(ret) { + case 0x001: // -inf + case 0x002: // -normal + case 0x004: // -subnormal + case 0x100: // sNaN + softfloat_exceptionFlags |= softfloat_flag_invalid; + case 0x200: //qNaN + uA.ui = defaultNaNBF16UI; + break; + case 0x008: // -0 + uA.ui = 0xff80; + softfloat_exceptionFlags |= softfloat_flag_infinite; + break; + case 0x010: // +0 + uA.ui = 0x7f80; + softfloat_exceptionFlags |= softfloat_flag_infinite; + break; + case 0x080: //+inf + uA.ui = 0x0; + break; + case 0x020: //+ sub + sub = true; + default: // +num + uA.ui = rsqrte7(uA.ui, 8, 7, sub); + break; + } + + return uA.f; +} + float16_t f16_rsqrte7(float16_t in) { union ui16_f16 uA; @@ -262,6 +299,49 @@ static inline uint64_t recip7(uint64_t val, int e, int s, int rm, bool sub, return (sign << (s+e)) | (out_exp << s) | out_sig; } +bfloat16_t bf16_recip7(bfloat16_t in) +{ + union ui16_bf16 uA; + + uA.f = in; + unsigned int ret = bf16_classify(in); + bool sub = false; + bool round_abnormal = false; + switch(ret) { + case 0x001: // -inf + uA.ui = 0x8000; + break; + case 0x080: //+inf + uA.ui = 0x0; + break; + case 0x008: // -0 + uA.ui = 0xff80; + softfloat_exceptionFlags |= softfloat_flag_infinite; + break; + case 0x010: // +0 + uA.ui = 0x7f80; + softfloat_exceptionFlags |= softfloat_flag_infinite; + break; + case 0x100: // sNaN + softfloat_exceptionFlags |= softfloat_flag_invalid; + case 0x200: //qNaN + uA.ui = defaultNaNBF16UI; + break; + case 0x004: // -subnormal + case 0x020: //+ sub + sub = true; + default: // +- normal + uA.ui = recip7(uA.ui, 8, 7, + softfloat_roundingMode, sub, &round_abnormal); + if (round_abnormal) + softfloat_exceptionFlags |= softfloat_flag_inexact | + softfloat_flag_overflow; + break; + } + + return uA.f; +} + float16_t f16_recip7(float16_t in) { union ui16_f16 uA; diff --git a/softfloat/fall_sign.c b/softfloat/fall_sign.c new file mode 100644 index 0000000..4e9c186 --- /dev/null +++ b/softfloat/fall_sign.c @@ -0,0 +1,63 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdio.h> +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +bool bf16_sign( bfloat16_t a ) +{ + return signBF16UI(a.v); +} + +bool f16_sign( float16_t a ) +{ + return signF16UI(a.v); +} + +bool f32_sign( float32_t a ) +{ + return signF32UI(a.v); +} + +bool f64_sign( float64_t a ) +{ + return signF64UI(a.v); +} diff --git a/softfloat/i32_to_bf16.c b/softfloat/i32_to_bf16.c new file mode 100644 index 0000000..e1f6ac8 --- /dev/null +++ b/softfloat/i32_to_bf16.c @@ -0,0 +1,52 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +bfloat16_t i32_to_bf16( int32_t a ) +{ + uint_fast8_t origin_rounding_mode = softfloat_roundingMode; + softfloat_roundingMode = softfloat_round_odd; + float32_t tmp_val = i32_to_f32(a); + + softfloat_roundingMode = origin_rounding_mode; + return f32_to_bf16(tmp_val); +} + diff --git a/softfloat/internals.h b/softfloat/internals.h index ae94427..f397ce5 100644 --- a/softfloat/internals.h +++ b/softfloat/internals.h @@ -46,6 +46,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif +union ui16_bf16 { uint16_t ui; bfloat16_t f; }; union ui16_f16 { uint16_t ui; float16_t f; }; union ui32_f32 { uint32_t ui; float32_t f; }; union ui64_f64 { uint64_t ui; float64_t f; }; @@ -84,16 +85,20 @@ int_fast64_t softfloat_roundMToI64( bool, uint32_t *, uint_fast8_t, bool ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ -#define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) -#define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) -#define fracF16UI( a ) ((a) & 0x03FF) -#define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) - #define signBF16UI( a ) ((bool) ((uint16_t) (a)>>15)) #define expBF16UI( a ) ((int_fast16_t) ((a)>>7) & 0xFF) #define fracBF16UI( a ) ((a) & 0x07F) #define packToBF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<7) + (sig)) +#define isNaNBF16UI( a ) (((~(a) & 0x7F80) == 0) && ((a) & 0x007F)) + +/*---------------------------------------------------------------------------- +*----------------------------------------------------------------------------*/ +#define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) +#define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) +#define fracF16UI( a ) ((a) & 0x03FF) +#define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) + #define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF)) struct exp8_sig16 { int_fast8_t exp; uint_fast16_t sig; }; diff --git a/softfloat/softfloat.h b/softfloat/softfloat.h index 81d63f3..9c57404 100644 --- a/softfloat/softfloat.h +++ b/softfloat/softfloat.h @@ -103,6 +103,7 @@ void softfloat_raiseFlags( uint_fast8_t ); /*---------------------------------------------------------------------------- | Integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ +bfloat16_t ui32_to_bf16( uint32_t ); float16_t ui32_to_f16( uint32_t ); float32_t ui32_to_f32( uint32_t ); float64_t ui32_to_f64( uint32_t ); @@ -121,6 +122,7 @@ float128_t ui64_to_f128( uint64_t ); #endif void ui64_to_extF80M( uint64_t, extFloat80_t * ); void ui64_to_f128M( uint64_t, float128_t * ); +bfloat16_t i32_to_bf16( int32_t ); float16_t i32_to_f16( int32_t ); float32_t i32_to_f32( int32_t ); float64_t i32_to_f64( int32_t ); @@ -180,6 +182,7 @@ bool f16_eq_signaling( float16_t, float16_t ); bool f16_le_quiet( float16_t, float16_t ); bool f16_lt_quiet( float16_t, float16_t ); bool f16_isSignalingNaN( float16_t ); +bool f16_sign( float16_t ); uint_fast16_t f16_classify( float16_t ); float16_t f16_rsqrte7( float16_t ); float16_t f16_recip7( float16_t ); @@ -187,6 +190,10 @@ float16_t f16_recip7( float16_t ); /*---------------------------------------------------------------------------- | BFloat16 operations. *----------------------------------------------------------------------------*/ +uint_fast8_t bf16_to_ui8( bfloat16_t, uint_fast8_t, bool ); +uint_fast32_t bf16_to_ui32( bfloat16_t, uint_fast8_t, bool ); +int_fast8_t bf16_to_i8( bfloat16_t, uint_fast8_t, bool ); +int_fast32_t bf16_to_i32( bfloat16_t, uint_fast8_t, bool ); float32_t bf16_to_f32( bfloat16_t ); float64_t bf16_to_f64( bfloat16_t ); bfloat16_t bf16_add( bfloat16_t, bfloat16_t ); @@ -195,6 +202,15 @@ bfloat16_t bf16_mul( bfloat16_t, bfloat16_t ); bfloat16_t bf16_mulAdd( bfloat16_t, bfloat16_t, bfloat16_t ); bfloat16_t bf16_div( bfloat16_t, bfloat16_t ); bfloat16_t bf16_sqrt( bfloat16_t ); +bfloat16_t bf16_max( bfloat16_t, bfloat16_t ); +bfloat16_t bf16_min( bfloat16_t, bfloat16_t ); +bool bf16_eq( bfloat16_t, bfloat16_t ); +bool bf16_le( bfloat16_t, bfloat16_t ); +bool bf16_lt( bfloat16_t, bfloat16_t ); +bool bf16_sign( bfloat16_t ); +uint_fast16_t bf16_classify( bfloat16_t ); +bfloat16_t bf16_rsqrte7( bfloat16_t ); +bfloat16_t bf16_recip7( bfloat16_t ); /*---------------------------------------------------------------------------- | 32-bit (single-precision) floating-point operations. @@ -235,6 +251,7 @@ bool f32_eq_signaling( float32_t, float32_t ); bool f32_le_quiet( float32_t, float32_t ); bool f32_lt_quiet( float32_t, float32_t ); bool f32_isSignalingNaN( float32_t ); +bool f32_sign( float32_t ); uint_fast16_t f32_classify( float32_t ); float32_t f32_rsqrte7( float32_t ); float32_t f32_recip7( float32_t ); @@ -276,6 +293,7 @@ bool f64_eq_signaling( float64_t, float64_t ); bool f64_le_quiet( float64_t, float64_t ); bool f64_lt_quiet( float64_t, float64_t ); bool f64_isSignalingNaN( float64_t ); +bool f64_sign( float64_t ); uint_fast16_t f64_classify( float64_t ); float64_t f64_rsqrte7( float64_t ); float64_t f64_recip7( float64_t ); diff --git a/softfloat/softfloat.mk.in b/softfloat/softfloat.mk.in index 626b611..899f00a 100644 --- a/softfloat/softfloat.mk.in +++ b/softfloat/softfloat.mk.in @@ -7,8 +7,14 @@ softfloat_c_srcs = \ bf16_mulAdd.c \ bf16_sqrt.c \ bf16_sub.c \ + bf16_cmp.c \ + bf16_classify.c \ bf16_to_f32.c \ bf16_to_f64.c \ + bf16_to_i8.c \ + bf16_to_i32.c \ + bf16_to_ui8.c \ + bf16_to_ui32.c \ f128_add.c \ f128_classify.c \ f128_div.c \ @@ -127,7 +133,9 @@ softfloat_c_srcs = \ f64_to_ui64_r_minMag.c \ fall_maxmin.c \ fall_reciprocal.c \ + fall_sign.c \ i32_to_f128.c \ + i32_to_bf16.c \ i32_to_f16.c \ i32_to_f32.c \ i32_to_f64.c \ @@ -228,6 +236,7 @@ softfloat_c_srcs = \ s_subMagsF64.c \ s_subM.c \ ui32_to_f128.c \ + ui32_to_bf16.c \ ui32_to_f16.c \ ui32_to_f32.c \ ui32_to_f64.c \ @@ -243,8 +252,5 @@ softfloat_test_srcs = softfloat_install_hdrs = \ softfloat.h \ softfloat_types.h \ - primitives.h \ - internals.h \ - platform.h \ - primitiveTypes.h \ - specialize.h \ + +softfloat_CFLAGS = -Wno-sign-compare -Wno-implicit-fallthrough diff --git a/softfloat/specialize.h b/softfloat/specialize.h index fb3761d..adbc081 100644 --- a/softfloat/specialize.h +++ b/softfloat/specialize.h @@ -105,6 +105,13 @@ struct commonNaN { char _unused; }; /*---------------------------------------------------------------------------- | Returns true when 16-bit unsigned integer `uiA' has the bit pattern of a +| 16-bit bfloating-point signaling NaN. +| Note: This macro evaluates its argument more than once. +*----------------------------------------------------------------------------*/ +#define softfloat_isSigNaNBF16UI( uiA ) ((((uiA) & 0x7FC0) == 0x7F80) && ((uiA) & 0x007F)) + +/*---------------------------------------------------------------------------- +| Returns true when 16-bit unsigned integer `uiA' has the bit pattern of a | 16-bit floating-point signaling NaN. | Note: This macro evaluates its argument more than once. *----------------------------------------------------------------------------*/ diff --git a/softfloat/ui32_to_bf16.c b/softfloat/ui32_to_bf16.c new file mode 100644 index 0000000..7b2d770 --- /dev/null +++ b/softfloat/ui32_to_bf16.c @@ -0,0 +1,51 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +bfloat16_t ui32_to_bf16( uint32_t a ) +{ + uint_fast8_t origin_rounding_mode = softfloat_roundingMode; + softfloat_roundingMode = softfloat_round_odd; + float32_t tmp_val = ui32_to_f32(a); + + softfloat_roundingMode = origin_rounding_mode; + return f32_to_bf16(tmp_val); +} + diff --git a/spike_dasm/spike-dasm.cc b/spike_dasm/spike-dasm.cc index 3e42df5..a093297 100644 --- a/spike_dasm/spike-dasm.cc +++ b/spike_dasm/spike-dasm.cc @@ -6,9 +6,9 @@ // enclosed hexadecimal number, interpreted as a RISC-V // instruction. -#include "config.h" #include "disasm.h" #include "extension.h" +#include "platform.h" #include <iostream> #include <string> #include <cstdint> @@ -19,6 +19,7 @@ int main(int UNUSED argc, char** argv) { string s; const char* isa = DEFAULT_ISA; + bool strict = false; std::function<extension_t*()> extension; option_parser_t parser; @@ -26,10 +27,11 @@ int main(int UNUSED argc, char** argv) parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);}); #endif parser.option(0, "isa", 1, [&](const char* s){isa = s;}); + parser.option(0, "strict", 0, [&](const char UNUSED *s){strict = true;}); parser.parse(argv); isa_parser_t isa_parser(isa, DEFAULT_PRIV); - disassembler_t* disassembler = new disassembler_t(&isa_parser); + disassembler_t* disassembler = new disassembler_t(&isa_parser, strict); if (extension) { for (auto disasm_insn : extension()->get_disasms()) { disassembler->add_insn(disasm_insn); diff --git a/spike_main/spike-log-parser.cc b/spike_main/spike-log-parser.cc index a054e95..21166ad 100644 --- a/spike_main/spike-log-parser.cc +++ b/spike_main/spike-log-parser.cc @@ -5,7 +5,6 @@ // in its inputs, then output the RISC-V instruction with the disassembly // enclosed hexadecimal number. -#include "config.h" #include <iostream> #include <string> #include <cstdint> @@ -14,6 +13,7 @@ #include "disasm.h" #include "extension.h" +#include "platform.h" using namespace std; @@ -31,14 +31,13 @@ int main(int UNUSED argc, char** argv) cfg_t cfg; isa_parser_t isa(isa_string, DEFAULT_PRIV); - processor_t p(&isa, &cfg, 0, 0, false, nullptr, cerr); + processor_t p(isa_string, DEFAULT_PRIV, &cfg, 0, 0, false, nullptr, cerr); if (extension) { p.register_extension(extension()); } std::regex reg("^core\\s+\\d+:\\s+0x[0-9a-f]+\\s+\\(0x([0-9a-f]+)\\)", std::regex_constants::icase); std::smatch m; - std::ssub_match sm ; while (getline(cin,s)){ if (regex_search(s, m, reg)){ diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 1a298f2..3b0e004 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -38,7 +38,7 @@ static void help(int exit_code = 1) fprintf(stderr, " -s Command I/O via socket (use with -d)\n"); #endif fprintf(stderr, " -h, --help Print this help message\n"); - fprintf(stderr, " -H Start halted, allowing a debugger to connect\n"); + fprintf(stderr, " --halted Start halted, allowing a debugger to connect\n"); fprintf(stderr, " --log=<name> File name for option -l\n"); fprintf(stderr, " --debug-cmd=<name> Read commands from file (use with -d)\n"); fprintf(stderr, " --isa=<name> RISC-V ISA string [default %s]\n", DEFAULT_ISA); @@ -78,12 +78,13 @@ static void help(int exit_code = 1) "required for a DMI access [default 0]\n"); fprintf(stderr, " --dm-abstract-rti=<n> Number of Run-Test/Idle cycles " "required for an abstract command to execute [default 0]\n"); - fprintf(stderr, " --dm-no-hasel Debug module supports hasel\n"); + fprintf(stderr, " --dm-no-hasel Debug module won't support hasel\n"); fprintf(stderr, " --dm-no-abstract-csr Debug module won't support abstract CSR access\n"); fprintf(stderr, " --dm-no-abstract-fpr Debug module won't support abstract FPR access\n"); fprintf(stderr, " --dm-no-halt-groups Debug module won't support halt groups\n"); fprintf(stderr, " --dm-no-impebreak Debug module won't support implicit ebreak in program buffer\n"); fprintf(stderr, " --blocksz=<size> Cache block size (B) for CMO operations(powers of 2) [default 64]\n"); + fprintf(stderr, " --instructions=<n> Stop after n instructions\n"); exit(exit_code); } @@ -191,6 +192,31 @@ merge_overlapping_memory_regions(std::vector<mem_cfg_t> mems) return merged_mem; } +static mem_cfg_t create_mem_region(unsigned long long base, unsigned long long size) +{ + // page-align base and size + auto base0 = base, size0 = size; + size += base0 % PGSIZE; + base -= base0 % PGSIZE; + if (size % PGSIZE != 0) + size += PGSIZE - size % PGSIZE; + + if (size != size0) { + fprintf(stderr, "Warning: the memory at [0x%llX, 0x%llX] has been realigned\n" + "to the %ld KiB page size: [0x%llX, 0x%llX]\n", + base0, base0 + size0 - 1, long(PGSIZE / 1024), base, base + size - 1); + } + + if (!mem_cfg_t::check_if_supported(base, size)) { + fprintf(stderr, "Unsupported memory region " + "{base = 0x%llX, size = 0x%llX} specified\n", + base, size); + exit(EXIT_FAILURE); + } + + return mem_cfg_t(base, size); +} + static std::vector<mem_cfg_t> parse_mem_layout(const char* arg) { std::vector<mem_cfg_t> res; @@ -200,9 +226,9 @@ static std::vector<mem_cfg_t> parse_mem_layout(const char* arg) auto mb = strtoull(arg, &p, 0); if (*p == 0) { reg_t size = reg_t(mb) << 20; - if (size != (size_t)size) - throw std::runtime_error("Size would overflow size_t"); - res.push_back(mem_cfg_t(reg_t(DRAM_BASE), size)); + if ((size >> 20) != mb) + throw std::runtime_error("Memory size too large"); + res.push_back(create_mem_region(DRAM_BASE, size)); return res; } @@ -213,42 +239,7 @@ static std::vector<mem_cfg_t> parse_mem_layout(const char* arg) help(); auto size = strtoull(p + 1, &p, 0); - // page-align base and size - auto base0 = base, size0 = size; - size += base0 % PGSIZE; - base -= base0 % PGSIZE; - if (size % PGSIZE != 0) - size += PGSIZE - size % PGSIZE; - - if (size != size0) { - fprintf(stderr, "Warning: the memory at [0x%llX, 0x%llX] has been realigned\n" - "to the %ld KiB page size: [0x%llX, 0x%llX]\n", - base0, base0 + size0 - 1, long(PGSIZE / 1024), base, base + size - 1); - } - - if (!mem_cfg_t::check_if_supported(base, size)) { - fprintf(stderr, "Unsupported memory region " - "{base = 0x%llX, size = 0x%llX} specified\n", - base, size); - exit(EXIT_FAILURE); - } - - const unsigned long long max_allowed_pa = (1ull << MAX_PADDR_BITS) - 1ull; - assert(max_allowed_pa <= std::numeric_limits<reg_t>::max()); - mem_cfg_t mem_region(base, size); - if (mem_region.get_inclusive_end() > max_allowed_pa) { - int bits_required = 64 - clz(mem_region.get_inclusive_end()); - fprintf(stderr, "Unsupported memory region " - "{base = 0x%" PRIX64 ", size = 0x%" PRIX64 "} specified," - " which requires %d bits of physical address\n" - " The largest accessible physical address " - "is 0x%llX (defined by MAX_PADDR_BITS constant, which is %d)\n", - mem_region.get_base(), mem_region.get_size(), bits_required, - max_allowed_pa, MAX_PADDR_BITS); - exit(EXIT_FAILURE); - } - - res.push_back(mem_region); + res.push_back(create_mem_region(base, size)); if (!*p) break; @@ -348,6 +339,7 @@ int main(int argc, char** argv) bool use_rbb = false; unsigned dmi_rti = 0; reg_t blocksz = 64; + std::optional<unsigned long long> instructions; debug_module_config_t dm_config; cfg_arg_t<size_t> nprocs(1); @@ -385,8 +377,7 @@ int main(int argc, char** argv) #endif parser.option('p', 0, 1, [&](const char* s){nprocs = atoul_nonzero_safe(s);}); parser.option('m', 0, 1, [&](const char* s){cfg.mem_layout = parse_mem_layout(s);}); - // I wanted to use --halted, but for some reason that doesn't work. - parser.option('H', 0, 0, [&](const char UNUSED *s){halted = true;}); + parser.option(0, "halted", 0, [&](const char UNUSED *s){halted = true;}); parser.option(0, "rbb-port", 1, [&](const char* s){use_rbb = true; rbb_port = atoul_safe(s);}); parser.option(0, "pc", 1, [&](const char* s){cfg.start_pc = strtoull(s, 0, 0);}); parser.option(0, "hartids", 1, [&](const char* s){ @@ -460,6 +451,10 @@ int main(int argc, char** argv) min_blocksz, max_blocksz); exit(-1); } + cfg.cache_blocksz = blocksz; + }); + parser.option(0, "instructions", 1, [&](const char* s){ + instructions = strtoull(s, 0, 0); }); auto argv1 = parser.parse(argv); @@ -522,7 +517,8 @@ int main(int argc, char** argv) sim_t s(&cfg, halted, mems, plugin_device_factories, htif_args, dm_config, log_path, dtb_enabled, dtb_file, socket, - cmd_file); + cmd_file, + instructions); std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL); std::unique_ptr<jtag_dtm_t> jtag_dtm( new jtag_dtm_t(&s.debug_module, dmi_rti)); @@ -546,7 +542,6 @@ int main(int argc, char** argv) if (dc) s.get_core(i)->get_mmu()->register_memtracer(&*dc); for (auto e : extensions) s.get_core(i)->register_extension(e()); - s.get_core(i)->get_mmu()->set_cache_blocksz(blocksz); } s.set_debug(debug); |