aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in9
-rw-r--r--README.md14
-rwxr-xr-xci-tests/build-spike2
-rwxr-xr-xci-tests/test-spike7
-rw-r--r--ci-tests/testlib.cc (renamed from ci-tests/testlib.c)0
-rw-r--r--disasm/disasm.cc68
-rw-r--r--disasm/isa_parser.cc10
-rw-r--r--fdt/libfdt.h4
-rw-r--r--fesvr/byteorder.h18
-rw-r--r--fesvr/elfloader.h1
-rw-r--r--riscv/cfg.cc7
-rw-r--r--riscv/csr_init.cc383
-rw-r--r--riscv/csrs.cc128
-rw-r--r--riscv/csrs.h22
-rw-r--r--riscv/decode_macros.h18
-rw-r--r--riscv/dts.cc156
-rw-r--r--riscv/dts.h11
-rw-r--r--riscv/encoding.h19
-rw-r--r--riscv/entropy_source.h5
-rw-r--r--riscv/execute.cc42
-rw-r--r--riscv/insn_template.cc47
-rw-r--r--riscv/insns/dret.h10
-rw-r--r--riscv/insns/fcvtmod_w_d.h3
-rw-r--r--riscv/insns/jal.h1
-rw-r--r--riscv/insns/jalr.h1
-rw-r--r--riscv/insns/mret.h3
-rw-r--r--riscv/insns/sret.h9
-rw-r--r--riscv/insns/vcompress_vm.h9
-rw-r--r--riscv/insns/vnclip_wi.h6
-rw-r--r--riscv/insns/vnclip_wv.h6
-rw-r--r--riscv/insns/vnclip_wx.h6
-rw-r--r--riscv/insns/vnclipu_wi.h6
-rw-r--r--riscv/insns/vnclipu_wv.h6
-rw-r--r--riscv/insns/vnclipu_wx.h6
-rw-r--r--riscv/insns/vsmul_vv.h8
-rw-r--r--riscv/insns/vsmul_vx.h8
-rw-r--r--riscv/insns/vssra_vi.h2
-rw-r--r--riscv/insns/vssra_vv.h2
-rw-r--r--riscv/insns/vssra_vx.h2
-rw-r--r--riscv/insns/vssrl_vi.h2
-rw-r--r--riscv/insns/vssrl_vv.h2
-rw-r--r--riscv/insns/vssrl_vx.h2
-rw-r--r--riscv/interactive.cc19
-rw-r--r--riscv/isa_parser.h4
-rw-r--r--riscv/mmu.cc118
-rw-r--r--riscv/mmu.h49
-rw-r--r--riscv/processor.cc466
-rw-r--r--riscv/processor.h23
-rw-r--r--riscv/riscv.mk.in1
-rw-r--r--riscv/sim.cc105
-rw-r--r--riscv/sim.h1
-rw-r--r--riscv/triggers.cc101
-rw-r--r--riscv/triggers.h4
-rw-r--r--riscv/v_ext_macros.h18
-rw-r--r--riscv/vector_unit.cc16
-rw-r--r--softfloat/softfloat.mk.in5
-rw-r--r--spike_main/spike-log-parser.cc2
-rw-r--r--spike_main/spike.cc68
58 files changed, 1223 insertions, 848 deletions
diff --git a/Makefile.in b/Makefile.in
index f90159e..d2d40e1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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 $^; \
diff --git a/README.md b/README.md
index 63f29eb..de1ac5f 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,6 +74,7 @@ Spike supports the following RISC-V ISA features:
- Zvkt extension, v1.0
- Zvkn, Zvknc, Zvkng extension, v1.0
- Zvks, Zvksc, Zvksg extension, v1.0
+ - Zicond extension, v1.0
- Zilsd extension, v0.9.0
- Zcmlsd extension, v0.9.0
diff --git a/ci-tests/build-spike b/ci-tests/build-spike
index 058defd..8774b5e 100755
--- a/ci-tests/build-spike
+++ b/ci-tests/build-spike
@@ -11,7 +11,7 @@ mkdir install
CXXFLAGS="-Wnon-virtual-dtor" CFLAGS="-Werror -Wignored-qualifiers -Wunused-function -Wunused-parameter -Wunused-variable" $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/test-spike b/ci-tests/test-spike
index 0540739..9826232 100755
--- a/ci-tests/test-spike
+++ b/ci-tests/test-spike
@@ -13,8 +13,11 @@ tar xf spike-ci.tar
time ../install/bin/spike --isa=rv64gc pk hello | grep "Hello, world! Pi is approximately 3.141588."
# 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
+
+# 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"
diff --git a/ci-tests/testlib.c b/ci-tests/testlib.cc
index 6bc0886..6bc0886 100644
--- a/ci-tests/testlib.c
+++ b/ci-tests/testlib.cc
diff --git a/disasm/disasm.cc b/disasm/disasm.cc
index c3ba62a..f1967d0 100644
--- a/disasm/disasm.cc
+++ b/disasm/disasm.cc
@@ -735,16 +735,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}));
@@ -1642,8 +1657,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 +1677,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 +1700,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 +1845,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 +1862,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 +1882,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 +1953,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 +1970,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 140bc87..95ef8fb 100644
--- a/disasm/isa_parser.cc
+++ b/disasm/isa_parser.cc
@@ -30,7 +30,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;
@@ -318,6 +318,12 @@ 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 {
@@ -349,6 +355,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) {
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..71ce515 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); }
@@ -22,17 +22,11 @@ static inline uint128_t swap(uint128_t n) { return (uint128_t(swap(uint64_t(n)))
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/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/riscv/cfg.cc b/riscv/cfg.cc
index 67dfdb4..2f9a229 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));
}
diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc
new file mode 100644
index 0000000..a03d188
--- /dev/null
+++ b/riscv/csr_init.cc
@@ -0,0 +1,383 @@
+#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::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));
+ 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));
+ 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);
+ add_hypervisor_csr(CSR_VSIP, vsip);
+ add_supervisor_csr(CSR_SIP, std::make_shared<virtualized_csr_t>(proc, nonvirtual_sip, vsip));
+ add_hypervisor_csr(CSR_HIP, std::make_shared<mip_proxy_csr_t>(proc, CSR_HIP, hip_hie_accr));
+ add_hypervisor_csr(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);
+ add_hypervisor_csr(CSR_VSIE, vsie);
+ add_supervisor_csr(CSR_SIE, std::make_shared<virtualized_csr_t>(proc, nonvirtual_sie, vsie));
+ 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));
+ 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));
+ 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));
+ add_hypervisor_csr(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) |
+ (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);
+ 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_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_stimecmp_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));
+
+
+ // 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);
+
+ const reg_t mireg_csrs[] = { CSR_MIREG, 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<basic_csr_t>(proc, CSR_VSISELECT, 0);
+ add_hypervisor_csr(CSR_VSISELECT, vsiselect);
+
+ csr_t_p siselect = std::make_shared<basic_csr_t>(proc, CSR_SISELECT, 0);
+ add_supervisor_csr(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 };
+ const reg_t sireg_csrs[] = { CSR_SIREG, 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));
+ }
+ }
+
+ 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));
+}
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 01720eb..7ea1e4f 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -197,13 +197,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 +286,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,6 +304,14 @@ bool mseccfg_csr_t::get_rlb() const noexcept {
return (read() & MSECCFG_RLB);
}
+bool mseccfg_csr_t::get_useed() const noexcept {
+ return (read() & MSECCFG_USEED);
+}
+
+bool mseccfg_csr_t::get_sseed() const noexcept {
+ return (read() & MSECCFG_SSEED);
+}
+
bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
if (proc->n_pmp == 0)
return false;
@@ -321,6 +331,11 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
new_val |= (val & MSECCFG_MMWP); //MMWP is sticky
new_val |= (val & MSECCFG_MML); //MML is sticky
+ if (proc->extension_enabled(EXT_ZKR)) {
+ uint64_t mask = MSECCFG_USEED | MSECCFG_SSEED;
+ new_val = (new_val & ~mask) | (val & mask);
+ }
+
proc->get_mmu()->flush_tlb();
if (proc->extension_enabled(EXT_ZICFILP)) {
@@ -328,6 +343,12 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
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);
}
@@ -527,13 +548,17 @@ 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);
+ if (new_mstatus & MSTATUS_MDT) {
+ new_mstatus = new_mstatus & ~MSTATUS_MIE;
+ }
maybe_flush_tlb(new_mstatus);
this->val = adjust_sd(new_mstatus);
return true;
@@ -548,6 +573,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
}
@@ -642,11 +668,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;
}
@@ -722,9 +743,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);
}
}
@@ -930,6 +951,7 @@ 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));
}
@@ -953,7 +975,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);
}
@@ -1318,6 +1348,8 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr):
halt(false),
v(false),
cause(0),
+ ext_cause(0),
+ cetrig(0),
pelp(elp_t::NO_LP_EXPECTED) {
}
@@ -1338,6 +1370,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);
@@ -1354,16 +1389,17 @@ 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_NMIP);
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;
@@ -1434,6 +1470,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 {
@@ -1451,7 +1497,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);
}
@@ -1472,7 +1518,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);
}
@@ -1561,6 +1607,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))
@@ -1571,7 +1629,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 | MENVCFG_DTE);
+ 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));
}
@@ -1622,9 +1680,9 @@ void scountovf_csr_t::verify_permissions(insn_t insn, bool write) const {
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, */
@@ -1752,8 +1810,6 @@ srmcfg_csr_t::srmcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_
}
void srmcfg_csr_t::verify_permissions(insn_t insn, bool write) const {
- csr_t::verify_permissions(insn, write);
-
if (!proc->extension_enabled(EXT_SSQOSID))
throw trap_illegal_instruction(insn.bits());
@@ -1764,6 +1820,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):
@@ -1798,3 +1858,23 @@ void mtval2_csr_t::verify_permissions(insn_t insn, bool write) const {
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);
+}
diff --git a/riscv/csrs.h b/riscv/csrs.h
index ad165b6..4055d86 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;
};
@@ -479,14 +481,13 @@ class envcfg_csr_t: public masked_csr_t {
// 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 | MENVCFG_DTE)) & 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:
@@ -683,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;
@@ -698,6 +699,8 @@ class dcsr_csr_t: public csr_t {
bool halt;
bool v;
uint8_t cause;
+ uint8_t ext_cause;
+ bool cetrig;
elp_t pelp;
};
@@ -786,7 +789,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 {
@@ -886,4 +893,11 @@ class mtval2_csr_t: public hypervisor_csr_t {
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;
+};
#endif
diff --git a/riscv/decode_macros.h b/riscv/decode_macros.h
index 675634a..1aa74fb 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) ({ \
@@ -167,7 +168,7 @@ static inline bool is_aligned(const unsigned val, const unsigned pos)
#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 +212,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) \
diff --git a/riscv/dts.cc b/riscv/dts.cc
index 8304171..9751ffe 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,44 @@ 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 void *prop;
+ 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 675b4f6..dff34ae 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 (6a1be96)
*/
#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=RS1 0x1f00000
#endif
#ifdef DECLARE_INSN
DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
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..e0a6e59 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -213,12 +213,11 @@ 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);
- } // !!!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 (state.dcsr->halt) {
+ enter_debug_mode(DCSR_CAUSE_HALT, 0);
}
}
@@ -257,7 +256,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 +285,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 +321,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 +350,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 +364,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/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/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/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/mret.h b/riscv/insns/mret.h
index 140ebde..71e488d 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);
+s = set_field(s, MSTATUS_MDT, 0);
if (prev_prv == PRV_U || prev_virt)
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/insns/vcompress_vm.h b/riscv/insns/vcompress_vm.h
index d35b8ba..45d2178 100644
--- a/riscv/insns/vcompress_vm.h
+++ b/riscv/insns/vcompress_vm.h
@@ -1,13 +1,14 @@
// vcompress vd, vs2, vs1
-require(P.VU.vstart->read() == 0);
-require_align(insn.rd(), P.VU.vflmul);
-require_align(insn.rs2(), P.VU.vflmul);
require(insn.rd() != insn.rs2());
-require_noover(insn.rd(), P.VU.vflmul, insn.rs1(), 1);
reg_t pos = 0;
VI_GENERAL_LOOP_BASE
+ require(P.VU.vstart->read() == 0);
+ require_align(insn.rd(), P.VU.vflmul);
+ require_align(insn.rs2(), P.VU.vflmul);
+ require_noover(insn.rd(), P.VU.vflmul, insn.rs1(), 1);
+
const int midx = i / 64;
const int mpos = i % 64;
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/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/vssra_vi.h b/riscv/insns/vssra_vi.h
index ff2e1c5..64a41a7 100644
--- a/riscv/insns/vssra_vi.h
+++ b/riscv/insns/vssra_vi.h
@@ -1,7 +1,7 @@
// vssra.vi vd, vs2, simm5
-VRM xrm = P.VU.get_vround_mode();
VI_VI_LOOP
({
+ VRM xrm = P.VU.get_vround_mode();
int sh = simm5 & (sew - 1) & 0x1f;
int128_t val = vs2;
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..9990235 100644
--- a/riscv/insns/vssrl_vi.h
+++ b/riscv/insns/vssrl_vi.h
@@ -1,7 +1,7 @@
// vssra.vi vd, vs2, simm5
-VRM xrm = P.VU.get_vround_mode();
VI_VI_ULOOP
({
+ VRM xrm = P.VU.get_vround_mode();
int sh = zimm5 & (sew - 1) & 0x1f;
uint128_t val = vs2;
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/interactive.cc b/riscv/interactive.cc
index 9a4b697..2701f49 100644
--- a/riscv/interactive.cc
+++ b/riscv/interactive.cc
@@ -342,8 +342,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)
@@ -473,15 +475,9 @@ void sim_t::interactive_insn(const std::string& cmd, const std::vector<std::stri
int max_xlen = p->get_isa().get_max_xlen();
std::ostream out(sout_.rdbuf());
- try
- {
- insn_t insn(get_insn(args));
- out << std::hex << std::setfill('0') << "0x" << std::setw(max_xlen/4)
- << zext(insn.bits(), max_xlen) << " " << p->get_disassembler()->disassemble(insn) << std::endl;
- }
- catch (trap_t& t) {
- out << "Unable to obtain insn due to " << t.name() << std::endl;
- }
+ 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;
}
void sim_t::interactive_priv(const std::string& cmd, const std::vector<std::string>& args)
@@ -717,8 +713,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 783af80..12cc52e 100644
--- a/riscv/isa_parser.h
+++ b/riscv/isa_parser.h
@@ -82,6 +82,10 @@ typedef enum {
EXT_ZICFILP,
EXT_ZICFISS,
EXT_SSDBLTRP,
+ EXT_SMDBLTRP,
+ EXT_SMMPM,
+ EXT_SMNPM,
+ EXT_SSNPM,
NUM_ISA_EXTENSIONS
} isa_extension_t;
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index d10e23a..38ecb65 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -5,6 +5,7 @@
#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),
@@ -54,7 +55,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;
@@ -192,9 +193,10 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool
void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_t access_info)
{
reg_t addr = access_info.vaddr;
- reg_t vpn = addr >> PGSHIFT;
+ reg_t transformed_addr = access_info.transformed_vaddr;
+ reg_t vpn = transformed_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;
+ auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr;
memcpy(bytes, host_addr, len);
return;
}
@@ -202,7 +204,7 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_
reg_t paddr = translate(access_info, len);
if (access_info.flags.lr && !sim->reservable(paddr)) {
- throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0);
+ throw trap_load_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
}
if (auto host_addr = sim->addr_to_mem(paddr)) {
@@ -213,7 +215,7 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_
refill_tlb(addr, paddr, host_addr, LOAD);
} else if (!mmio_load(paddr, len, bytes)) {
- throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0);
+ throw trap_load_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
}
if (access_info.flags.lr) {
@@ -221,42 +223,44 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_
}
}
-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);
+ 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 ((addr & (len - 1)) == 0) {
+ 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));
}
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));
}
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 addr = access_info.vaddr;
- reg_t vpn = addr >> PGSHIFT;
+ reg_t transformed_addr = access_info.transformed_vaddr;
+ reg_t vpn = transformed_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;
+ auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr;
memcpy(host_addr, bytes, len);
}
return;
@@ -272,34 +276,35 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces
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);
+ throw trap_store_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
}
}
}
-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);
+ 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);
@@ -399,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
@@ -484,7 +489,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 +501,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 +531,7 @@ 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);
if (pte & PTE_RSVD) {
break;
@@ -547,17 +553,17 @@ 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)) {
+ } else if (ss_page && (type == STORE && !ss_access)) {
// not shadow stack store and xwr = 010 cause 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) {
@@ -606,3 +612,53 @@ 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 || ((proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(effective_virt)) & MSTATUS_MXR) || flags.hlvx)
+ return 0;
+
+ reg_t pmm = 0;
+ if (effective_priv == PRV_M)
+ pmm = get_field(proc->state.mseccfg->read(), MSECCFG_PMM);
+ 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..1047a71 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
{
@@ -51,13 +51,14 @@ struct xlate_flags_t {
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};
+ return {vaddr + offset, transformed_vaddr + offset, effective_priv, effective_virt, flags, type};
}
};
@@ -71,24 +72,8 @@ 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);
@@ -236,24 +221,30 @@ public:
}
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, {});
+ 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(generate_access_info(transformed_addr, LOAD, {}), 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);
}
})
}
@@ -416,9 +407,9 @@ private:
// 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);
+ 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 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);
bool mmio_fetch(reg_t paddr, size_t len, uint8_t* bytes);
bool mmio_load(reg_t paddr, size_t len, uint8_t* bytes);
@@ -490,7 +481,7 @@ private:
return (uint16_t*)(translate_insn_addr(addr).host_offset + addr);
}
- inline bool in_mprv()
+ inline bool in_mprv() const
{
return proc != nullptr
&& !(proc->state.mnstatus && !get_field(proc->state.mnstatus->read(), MNSTATUS_NMIE))
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 7a6989e..60f6a89 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -30,49 +30,50 @@
#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(0),
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);
- 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);
@@ -140,409 +141,15 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
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<mtval2_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) |
- (proc->extension_enabled(EXT_SSDBLTRP) ? MENVCFG_DTE : 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) |
- (proc->extension_enabled(EXT_SSDBLTRP) ? HENVCFG_DTE : 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();
@@ -551,6 +158,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)
@@ -573,11 +184,12 @@ void processor_t::enable_log_commits()
void processor_t::reset()
{
- xlen = isa->get_max_xlen();
- state.reset(this, isa->get_max_isa());
+ xlen = isa.get_max_xlen();
+ state.reset(this, isa.get_max_isa());
state.dcsr->halt = halt_on_reset;
halt_on_reset = false;
- VU.reset();
+ if (any_vector_extensions())
+ VU.reset();
in_wfi = false;
if (n_pmp > 0) {
@@ -721,7 +333,7 @@ void processor_t::take_interrupt(reg_t pending_interrupts)
abort();
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(enabled_interrupts));
}
}
@@ -769,11 +381,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);
@@ -793,7 +405,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
@@ -890,10 +502,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());
@@ -901,7 +526,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);
@@ -911,7 +535,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);
}
}
@@ -927,7 +551,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);
@@ -971,7 +595,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)
@@ -990,7 +614,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;
}
@@ -1117,7 +741,7 @@ void processor_t::register_base_instructions()
// add overlapping instructions first, in order
#define DECLARE_OVERLAP_INSN(name, ext) \
name##_overlapping = true; \
- if (isa->extension_enabled(ext)) \
+ if (isa.extension_enabled(ext)) \
register_base_insn((insn_desc_t) { \
name##_match, \
name##_mask, \
diff --git a/riscv/processor.h b/riscv/processor.h
index 14b828c..4f22cbd 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;
@@ -70,6 +71,7 @@ typedef std::vector<std::tuple<reg_t, uint64_t, uint8_t>> commit_log_mem_t;
struct state_t
{
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;
@@ -97,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;
@@ -167,8 +170,6 @@ struct state_t
csr_t_p stimecmp;
csr_t_p vstimecmp;
- csr_t_p srmcfg;
-
csr_t_p ssp;
bool serialized; // whether timer CSRs are in a well-defined state
@@ -189,6 +190,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,12 +242,13 @@ 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 isa_parser_t &get_isa() { return isa; }
const cfg_t &get_cfg() { return *cfg; }
void set_debug(bool value);
@@ -303,7 +310,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 {
@@ -362,7 +369,7 @@ public:
void check_if_lpad_required();
private:
- const isa_parser_t * const isa;
+ const isa_parser_t isa;
const cfg_t * const cfg;
simif_t* sim;
@@ -401,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.mk.in b/riscv/riscv.mk.in
index 60723b5..bc512bf 100644
--- a/riscv/riscv.mk.in
+++ b/riscv/riscv.mk.in
@@ -68,6 +68,7 @@ riscv_srcs = \
remote_bitbang.cc \
jtag_dtm.cc \
csrs.cc \
+ csr_init.cc \
triggers.cc \
vector_unit.cc \
socketif.cc \
diff --git a/riscv/sim.cc b/riscv/sim.cc
index d08e274..d47ceae 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -46,10 +46,8 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
bool socket_enabled,
FILE *cmd_file) // needed for command line option --cmd
: 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),
@@ -98,14 +96,16 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
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];
- }
-
// 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,6 +133,7 @@ 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;
@@ -141,11 +142,8 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
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 +160,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 +174,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);
+ }
+
+ 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
+ // handle pmp
reg_t pmp_num, pmp_granularity;
if (fdt_parse_pmp_num(fdt, cpu_offset, &pmp_num) != 0)
pmp_num = 0;
@@ -206,7 +210,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 +224,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
@@ -235,12 +239,22 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
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 +270,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 +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/sim.h b/riscv/sim.h
index 540d80d..93a2c21 100644
--- a/riscv/sim.h
+++ b/riscv/sim.h
@@ -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;
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 3e8a653..b6365aa 100644
--- a/riscv/v_ext_macros.h
+++ b/riscv/v_ext_macros.h
@@ -1144,32 +1144,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; \
@@ -1202,10 +1202,10 @@ reg_t index[P.VU.vlmax]; \
#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); \
@@ -1220,12 +1220,12 @@ reg_t index[P.VU.vlmax]; \
#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_ELEMENT_SKIP; \
@@ -1256,10 +1256,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,12 +1274,12 @@ 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_STRIP(i) \
@@ -1310,10 +1310,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); \
diff --git a/riscv/vector_unit.cc b/riscv/vector_unit.cc
index 08adc61..a5c35f8 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
diff --git a/softfloat/softfloat.mk.in b/softfloat/softfloat.mk.in
index 626b611..e6e3998 100644
--- a/softfloat/softfloat.mk.in
+++ b/softfloat/softfloat.mk.in
@@ -243,8 +243,3 @@ softfloat_test_srcs =
softfloat_install_hdrs = \
softfloat.h \
softfloat_types.h \
- primitives.h \
- internals.h \
- platform.h \
- primitiveTypes.h \
- specialize.h \
diff --git a/spike_main/spike-log-parser.cc b/spike_main/spike-log-parser.cc
index a054e95..55ff999 100644
--- a/spike_main/spike-log-parser.cc
+++ b/spike_main/spike-log-parser.cc
@@ -31,7 +31,7 @@ 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());
}
diff --git a/spike_main/spike.cc b/spike_main/spike.cc
index 1a298f2..d656d64 100644
--- a/spike_main/spike.cc
+++ b/spike_main/spike.cc
@@ -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;