aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md18
-rwxr-xr-xci-tests/create-ci-binary-tarball11
-rw-r--r--ci-tests/custom-csr.cc81
-rw-r--r--ci-tests/customcsr.c12
-rwxr-xr-xci-tests/test-spike2
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure33
-rw-r--r--configure.ac2
-rw-r--r--disasm/disasm.cc71
-rw-r--r--disasm/isa_parser.cc42
-rw-r--r--fesvr/htif_pthread.h2
-rw-r--r--riscv/cfg.cc6
-rw-r--r--riscv/csr_init.cc7
-rw-r--r--riscv/csrs.cc24
-rw-r--r--riscv/csrs.h5
-rw-r--r--riscv/debug_module.cc4
-rw-r--r--riscv/decode_macros.h6
-rw-r--r--riscv/dts.cc21
-rw-r--r--riscv/dts.h3
-rw-r--r--riscv/encoding.h19
-rw-r--r--riscv/execute.cc43
-rw-r--r--riscv/extension.h1
-rw-r--r--riscv/insn_template.cc47
-rw-r--r--riscv/insns/c_ld.h2
-rw-r--r--riscv/insns/c_ldsp.h2
-rw-r--r--riscv/insns/c_sd.h2
-rw-r--r--riscv/insns/c_sdsp.h2
-rw-r--r--riscv/insns/dret.h10
-rw-r--r--riscv/insns/jal.h1
-rw-r--r--riscv/insns/jalr.h1
-rw-r--r--riscv/insns/mret.h5
-rw-r--r--riscv/insns/sret.h9
-rw-r--r--riscv/isa_parser.h3
-rw-r--r--riscv/log_file.h2
-rw-r--r--riscv/mmu.cc18
-rw-r--r--riscv/mmu.h9
-rw-r--r--riscv/platform.h2
-rw-r--r--riscv/plic.cc2
-rw-r--r--riscv/processor.cc36
-rw-r--r--riscv/processor.h7
-rw-r--r--riscv/riscv.ac12
-rw-r--r--riscv/sim.cc11
-rw-r--r--riscv/triggers.cc101
-rw-r--r--riscv/triggers.h4
-rw-r--r--riscv/v_ext_macros.h2
-rw-r--r--softfloat/f64_to_bf16.c46
-rw-r--r--spike_dasm/spike-dasm.cc2
-rw-r--r--spike_main/spike-log-parser.cc2
-rw-r--r--spike_main/spike.cc73
49 files changed, 556 insertions, 276 deletions
diff --git a/README.md b/README.md
index 63f29eb..7d1b207 100644
--- a/README.md
+++ b/README.md
@@ -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
@@ -37,11 +39,22 @@ Spike supports the following RISC-V ISA features:
- Svnapot extension, v1.0
- Svpbmt extension, v1.0
- Svinval extension, v1.0
+ - Svadu 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 +74,9 @@ 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, v0.10
+ - Zclsd extension, v0.10
Versioning and APIs
-------------------
diff --git a/ci-tests/create-ci-binary-tarball b/ci-tests/create-ci-binary-tarball
index abc9ee0..73a549e 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,14 @@ 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 -
+
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 .
+tar -cf spike-ci.tar pk hello dummy-slliuw customcsr
-rm pk hello dummy-slliuw
+rm pk hello dummy-slliuw customcsr
diff --git a/ci-tests/custom-csr.cc b/ci-tests/custom-csr.cc
new file mode 100644
index 0000000..a605dc3
--- /dev/null
+++ b/ci-tests/custom-csr.cc
@@ -0,0 +1,81 @@
+#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() { return "dummycsr"; }
+
+ xdummycsr_t() {}
+
+ std::vector<insn_desc_t> get_instructions() override {
+ return {};
+ }
+
+ std::vector<disasm_insn_t *> get_disasms() 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
+ 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-spike b/ci-tests/test-spike
index 9826232..36b748a 100755
--- a/ci-tests/test-spike
+++ b/ci-tests/test-spike
@@ -15,9 +15,11 @@ time ../install/bin/spike --isa=rv64gc pk hello | grep "Hello, world! Pi is app
# check that including sim.h in an external project works
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/config.h.in b/config.h.in
index aef3596..a8918c6 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
diff --git a/configure b/configure
index 4ad998a..e701421 100755
--- a/configure
+++ b/configure
@@ -737,8 +737,6 @@ with_boost
with_boost_libdir
with_boost_asio
with_boost_regex
-with_isa
-with_priv
with_target
enable_dual_endian
'
@@ -1403,9 +1401,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
@@ -6562,34 +6557,6 @@ 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 :
diff --git a/configure.ac b/configure.ac
index 701bd99..b46dc15 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:
#
diff --git a/disasm/disasm.cc b/disasm/disasm.cc
index c3ba62a..a2acd4e 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>
@@ -735,16 +736,31 @@ static void NOINLINE add_vector_vv_insn(disassembler_t* d, const char* name, uin
d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, &vs1, opt, &vm}));
}
+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, {&vd, &vs1, &vs2, opt, &vm}));
+}
+
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, {&vd, &vs2, &xrs1, opt, &vm}));
}
+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, &xrs1, &vs2, 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}));
}
+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, &frs1, &vs2, opt, &vm}));
+}
+
static void NOINLINE add_vector_vi_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, &v_simm5, opt, &vm}));
@@ -1497,7 +1513,7 @@ void disassembler_t::add_instructions(const isa_parser_t* isa)
DISASM_INSN("c.addiw", c_addiw, 0, {&xrd, &rvc_imm});
}
- if (isa->get_max_xlen() == 64 || isa->extension_enabled(EXT_ZCMLSD)) {
+ if (isa->get_max_xlen() == 64 || isa->extension_enabled(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});
@@ -1642,8 +1658,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 +1678,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 +1701,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 +1846,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 +1863,10 @@ 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);
#undef DISASM_OPIV_VXI_INSN
#undef DISASM_OPIV_VX__INSN
@@ -1858,6 +1883,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 +1954,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 +1971,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
diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc
index 79203df..69c3e34 100644
--- a/disasm/isa_parser.cc
+++ b/disasm/isa_parser.cc
@@ -9,6 +9,26 @@ static std::string strtolower(const char* str)
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 +50,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;
@@ -247,8 +267,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") {
@@ -327,17 +347,17 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
} 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;
}
@@ -355,6 +375,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
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[0] == 'x') {
extension_table['X'] = true;
if (ext_str.size() == 1) {
@@ -394,12 +416,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/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/riscv/cfg.cc b/riscv/cfg.cc
index 8763240..2f9a229 100644
--- a/riscv/cfg.cc
+++ b/riscv/cfg.cc
@@ -18,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));
}
diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc
index d72c925..a03d188 100644
--- a/riscv/csr_init.cc
+++ b/riscv/csr_init.cc
@@ -86,7 +86,6 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
add_csr(which_mevent, mevent[i]);
}
}
- add_csr(CSR_MCOUNTINHIBIT, std::make_shared<const_csr_t>(proc, CSR_MCOUNTINHIBIT, 0));
add_const_ext_csr(EXT_SSCOFPMF, CSR_SCOUNTOVF, std::make_shared<scountovf_csr_t>(proc, CSR_SCOUNTOVF));
add_csr(CSR_MIE, mie = std::make_shared<mie_csr_t>(proc, CSR_MIE));
add_csr(CSR_MIP, mip = std::make_shared<mip_csr_t>(proc, CSR_MIP));
@@ -134,6 +133,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
add_supervisor_csr(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);
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));
@@ -205,13 +205,14 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
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));
- add_csr(CSR_TCONTROL, tcontrol = std::make_shared<masked_csr_t>(proc, CSR_TCONTROL, CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE, 0));
+ 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));
- add_csr(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
add_supervisor_csr(CSR_SCONTEXT, scontext = std::make_shared<masked_csr_t>(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0));
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 6fdd6a3..a62f63a 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -548,13 +548,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;
@@ -569,6 +572,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
}
@@ -1340,9 +1344,10 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr):
ebreaku(false),
ebreakvs(false),
ebreakvu(false),
- halt(false),
v(false),
cause(0),
+ ext_cause(0),
+ cetrig(0),
pelp(elp_t::NO_LP_EXPECTED) {
}
@@ -1363,6 +1368,9 @@ reg_t dcsr_csr_t::read() const noexcept {
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);
@@ -1382,12 +1390,14 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept {
v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false;
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;
@@ -1400,8 +1410,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)) {
@@ -1421,7 +1432,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);
}
diff --git a/riscv/csrs.h b/riscv/csrs.h
index db61fba..278bdb3 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -684,7 +684,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 +696,10 @@ class dcsr_csr_t: public csr_t {
bool ebreaku;
bool ebreakvs;
bool ebreakvu;
- bool halt;
bool v;
uint8_t cause;
+ uint8_t ext_cause;
+ bool cetrig;
elp_t pelp;
};
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc
index 5d49605..7c59744 100644
--- a/riscv/debug_module.cc
+++ b/riscv/debug_module.cc
@@ -462,9 +462,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/decode_macros.h b/riscv/decode_macros.h
index 0f32a3a..807ad98 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,7 +165,6 @@ 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(p->any_vector_extensions() && STATE.sstatus->enabled(SSTATUS_VS))
diff --git a/riscv/dts.cc b/riscv/dts.cc
index 7ca7c4e..9751ffe 100644
--- a/riscv/dts.cc
+++ b/riscv/dts.cc
@@ -99,13 +99,10 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
return s.str();
}
-std::string dtc_compile(const std::string& dtc_input, const std::string& input_type, const std::string& output_type)
+static std::string dtc_compile(const std::string& dtc_input, bool compile)
{
- if (input_type == output_type)
- std::cerr << "Must have differing {in,out}put types for running " DTC << std::endl;
-
- if (!((input_type == "dts" && output_type == "dtb") || (input_type == "dtb" && output_type == "dts")))
- std::cerr << "Invalid {in,out}put types for running " DTC ": Must convert from 'dts' to 'dtb' (or vice versa)" << std::endl;
+ const char* input_type = compile ? "dts" : "dtb";
+ const char* output_type = compile ? "dtb" : "dts";
int dtc_input_pipe[2];
pid_t dtc_input_pid;
@@ -147,7 +144,7 @@ std::string dtc_compile(const std::string& dtc_input, const std::string& input_t
close(dtc_input_pipe[1]);
close(dtc_output_pipe[0]);
close(dtc_output_pipe[1]);
- execlp(DTC, DTC, "-O", output_type.c_str(), "-I", input_type.c_str(), (char *)0);
+ execlp(DTC, DTC, "-O", output_type, "-I", input_type, nullptr);
std::cerr << "Failed to run " DTC ": " << strerror(errno) << std::endl;
exit(1);
}
@@ -186,6 +183,16 @@ std::string dtc_compile(const std::string& dtc_input, const std::string& input_t
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,
unsigned long *size, const char *field)
{
diff --git a/riscv/dts.h b/riscv/dts.h
index 987f269..730dea7 100644
--- a/riscv/dts.h
+++ b/riscv/dts.h
@@ -11,7 +11,8 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
std::vector<std::pair<reg_t, abstract_mem_t*>> mems,
std::string device_nodes);
-std::string dtc_compile(const std::string& dtc_input, const std::string& input_type, const std::string& output_type);
+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);
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 675b4f6..dcd4e24 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 (c55d30f)
+ * https://github.com/riscv/riscv-opcodes (47862ce)
*/
#ifndef RISCV_CSR_ENCODING_H
@@ -110,6 +110,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))
@@ -117,7 +120,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)
@@ -220,6 +223,17 @@
#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
@@ -3005,6 +3019,7 @@
#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)
diff --git a/riscv/execute.cc b/riscv/execute.cc
index cc77d88..1fa6111 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -213,12 +213,12 @@ void processor_t::step(size_t n)
{
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);
- }
- 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);
}
}
@@ -257,7 +257,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 +286,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,13 +322,23 @@ 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)
@@ -330,7 +351,7 @@ void processor_t::step(size_t n)
}
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 +365,12 @@ void processor_t::step(size_t n)
in_wfi = true;
}
- state.minstret->bump(instret);
+ if (!(state.mcountinhibit->read() & MCOUNTINHIBIT_IR))
+ state.minstret->bump(instret);
// Model a hart whose CPI is 1.
- state.mcycle->bump(instret);
+ if (!(state.mcountinhibit->read() & MCOUNTINHIBIT_CY))
+ state.mcycle->bump(instret);
n -= instret;
}
diff --git a/riscv/extension.h b/riscv/extension.h
index de6ece3..991da7e 100644
--- a/riscv/extension.h
+++ b/riscv/extension.h
@@ -13,6 +13,7 @@ class extension_t
public:
virtual std::vector<insn_desc_t> get_instructions() = 0;
virtual std::vector<disasm_insn_t*> get_disasms() = 0;
+ virtual std::vector<csr_t_p> get_csrs ([[maybe_unused]] processor_t &proc) const { return {}; };
virtual const char* name() = 0;
virtual void reset() {};
virtual void set_debug(bool UNUSED value) {}
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/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 60aaf21..0f94f88 100644
--- a/riscv/insns/dret.h
+++ b/riscv/insns/dret.h
@@ -4,8 +4,16 @@ 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);
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/mret.h b/riscv/insns/mret.h
index 140ebde..479bfca 100644
--- a/riscv/insns/mret.h
+++ b/riscv/insns/mret.h
@@ -13,11 +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);
-if (prev_prv == PRV_U || prev_virt)
+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 fe007d3..efb4fa6 100644
--- a/riscv/insns/sret.h
+++ b/riscv/insns/sret.h
@@ -26,6 +26,15 @@ 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) {
diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h
index 45f637c..90e1ec1 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,
@@ -82,6 +82,7 @@ typedef enum {
EXT_ZICFILP,
EXT_ZICFISS,
EXT_SSDBLTRP,
+ EXT_SMDBLTRP,
EXT_SMMPM,
EXT_SMNPM,
EXT_SSNPM,
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 94997a2..8b99c1d 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -404,7 +404,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
@@ -553,8 +553,8 @@ 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 (ss_page && (type == STORE && !ss_access)) {
- // not shadow stack store and xwr = 010 cause access-fault
+ } 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 (ss_page && type == FETCH) {
// fetch from shadow stack pages cause instruction access-fault
@@ -614,7 +614,7 @@ void mmu_t::register_memtracer(memtracer_t* 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 || (in_mprv() && (proc->state.sstatus->read() & MSTATUS_MXR)) || flags.hlvx)
+ if (!proc || proc->get_xlen() != 64 || ((proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(effective_virt)) & MSTATUS_MXR) || flags.hlvx)
return 0;
reg_t pmm = 0;
@@ -643,6 +643,7 @@ mem_access_info_t mmu_t::generate_access_info(reg_t addr, access_type type, xlat
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);
@@ -653,10 +654,11 @@ mem_access_info_t mmu_t::generate_access_info(reg_t addr, access_type type, xlat
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);
}
- 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;
- reg_t transformed_addr = is_physical_addr ? zext(addr, 64 - pmlen) : sext(addr, 64 - pmlen);
return {addr, transformed_addr, mode, virt, xlate_flags, type};
}
diff --git a/riscv/mmu.h b/riscv/mmu.h
index 0aa1f96..224b8f5 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -19,7 +19,7 @@
#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
struct insn_fetch_t
{
@@ -43,9 +43,10 @@ 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;
}
};
@@ -232,14 +233,14 @@ public:
}
void clean_inval(reg_t addr, bool clean, bool inval) {
- auto access_info = generate_access_info(addr, LOAD, {});
+ 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, transformed_addr, std::nullopt);
convert_load_traps_to_store_traps({
- const reg_t paddr = translate(generate_access_info(transformed_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);
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..14de6df 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
diff --git a/riscv/processor.cc b/riscv/processor.cc
index d480f8f..ecdf392 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -159,6 +159,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
elp = elp_t::NO_LP_EXPECTED;
+ critical_error = false;
+
csr_init(proc, max_isa);
}
@@ -184,8 +186,6 @@ 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;
if (any_vector_extensions())
VU.reset();
in_wfi = false;
@@ -304,8 +304,8 @@ void processor_t::take_interrupt(reg_t pending_interrupts)
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);
+ 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;
@@ -379,11 +379,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);
@@ -444,7 +444,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
// 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))) {
- reg_t s = curr_virt ? state.nonvirtual_sstatus->read() : state.sstatus->read();
+ reg_t s = state.sstatus->read();
supv_double_trap = get_field(s, MSTATUS_SDT);
if (supv_double_trap)
vsdeleg = hsdeleg = 0;
@@ -500,10 +500,23 @@ 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(supv_double_trap ? CAUSE_DOUBLE_TRAP : t.cause());
@@ -511,7 +524,6 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
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);
@@ -521,7 +533,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);
}
}
@@ -537,7 +549,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);
@@ -699,6 +711,8 @@ void processor_t::register_extension(extension_t *x) {
fprintf(stderr, "extensions must have unique names (got two named \"%s\"!)\n", x->name());
abort();
}
+ for (auto &csr: x->get_csrs(*this))
+ state.add_csr(csr->address, csr);
x->set_processor(this);
}
diff --git a/riscv/processor.h b/riscv/processor.h
index 26d0878..4f22cbd 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -62,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;
@@ -99,6 +99,7 @@ struct state_t
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;
@@ -190,6 +191,8 @@ struct state_t
elp_t elp;
+ bool critical_error;
+
private:
void csr_init(processor_t* const proc, reg_t max_isa);
};
@@ -405,7 +408,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..cd7cfe2 100644
--- a/riscv/riscv.ac
+++ b/riscv/riscv.ac
@@ -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/sim.cc b/riscv/sim.cc
index e9928f5..d47ceae 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -103,8 +103,8 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
cfg, this, cfg->hartids[i], halted,
log_file.get(), sout_));
harts[cfg->hartids[i]] = procs[i];
- return;
}
+ return;
} // otherwise, generate the procs by parsing the DTS
// Only make a CLINT (Core-Local INTerrupt controller) and PLIC (Platform-
@@ -133,7 +133,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
std::stringstream strstream;
strstream << fin.rdbuf();
dtb = strstream.str();
- dts = dtc_compile(dtb, "dtb", "dts");
+ dts = dtb_to_dts(dtb);
} else {
std::pair<reg_t, reg_t> initrd_bounds = cfg->initrd_bounds;
std::string device_nodes;
@@ -143,7 +143,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
device_nodes.append(factory->generate_dts(this, sargs));
}
dts = make_dts(INSNS_PER_RTC_TICK, CPU_HZ, cfg, mems, device_nodes);
- dtb = dtc_compile(dts, "dts", "dtb");
+ dtb = dts_to_dtb(dts);
}
int fdt_code = fdt_check_header(dtb.c_str());
@@ -195,7 +195,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
exit(1);
}
- procs.push_back(new processor_t(isa_str, DEFAULT_PRIV,
+ procs.push_back(new processor_t(isa_str, cfg->priv,
cfg, this, hartid, halted,
log_file.get(), sout_));
harts[hartid] = procs[cpu_idx];
@@ -336,7 +336,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)
diff --git a/riscv/triggers.cc b/riscv/triggers.cc
index de3da40..e130a87 100644
--- a/riscv/triggers.cc
+++ b/riscv/triggers.cc
@@ -55,12 +55,54 @@ void trigger_t::tdata3_write(processor_t * const proc, const reg_t val) noexcept
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);
}
+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,11 @@ 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_NAPOT: if (maskmax == 0) return MATCH_EQUAL;
case MATCH_EQUAL:
- case MATCH_NAPOT:
case MATCH_GE:
case MATCH_LT:
case MATCH_MASK_LOW:
@@ -261,7 +292,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 +328,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 +351,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 +366,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 +458,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);
}
diff --git a/riscv/triggers.h b/riscv/triggers.h
index 24f9206..3f1e86f 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 {
diff --git a/riscv/v_ext_macros.h b/riscv/v_ext_macros.h
index b6365aa..3e7dc45 100644
--- a/riscv/v_ext_macros.h
+++ b/riscv/v_ext_macros.h
@@ -491,7 +491,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) \
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/spike_dasm/spike-dasm.cc b/spike_dasm/spike-dasm.cc
index 3e42df5..547f044 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>
diff --git a/spike_main/spike-log-parser.cc b/spike_main/spike-log-parser.cc
index 55ff999..2c9a543 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;
diff --git a/spike_main/spike.cc b/spike_main/spike.cc
index 1a298f2..69ce256 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);
@@ -191,6 +191,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 +225,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 +238,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;
@@ -385,8 +375,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){