diff options
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 $^; \ @@ -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; |