diff options
49 files changed, 585 insertions, 365 deletions
diff --git a/Makefile.in b/Makefile.in index d2d40e1..66d087b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,7 +93,7 @@ VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled)) # These all appear on the command line, from lowest precedence to # highest. -default-CFLAGS := -DPREFIX=\"$(prefix)\" -Wall -Wno-unused -Wno-nonportable-include-path -g -O2 -fPIC +default-CFLAGS := -DPREFIX=\"$(prefix)\" -Wall -Wno-nonportable-include-path -g -O2 -fPIC default-CXXFLAGS := $(default-CFLAGS) -std=c++2a mcppbs-CPPFLAGS := @CPPFLAGS@ diff --git a/ci-tests/build-spike b/ci-tests/build-spike index 8774b5e..0a1b315 100755 --- a/ci-tests/build-spike +++ b/ci-tests/build-spike @@ -8,7 +8,7 @@ rm -rf build mkdir build cd build mkdir install -CXXFLAGS="-Wnon-virtual-dtor" CFLAGS="-Werror -Wignored-qualifiers -Wunused-function -Wunused-parameter -Wunused-variable" $DIR/../configure --prefix=`pwd`/install +CXXFLAGS="-Wnon-virtual-dtor" CFLAGS="-Werror -Wall -Wextra -Wvla" $DIR/../configure --prefix=`pwd`/install make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" make check make install install-hdrs-list.h diff --git a/ci-tests/custom-csr.cc b/ci-tests/custom-csr.cc index 90fef01..857c9c3 100644 --- a/ci-tests/custom-csr.cc +++ b/ci-tests/custom-csr.cc @@ -20,15 +20,15 @@ class dummycsr_t: public csr_t { // dummy extension with dummy CSRs. Nice. struct xdummycsr_t : public extension_t { - const char *name() { return "dummycsr"; } + const char *name() const override { return "dummycsr"; } xdummycsr_t() {} - std::vector<insn_desc_t> get_instructions() override { + std::vector<insn_desc_t> get_instructions(const processor_t &) override { return {}; } - std::vector<disasm_insn_t *> get_disasms() override { + std::vector<disasm_insn_t *> get_disasms(const processor_t *) override { return {}; } diff --git a/ci-tests/test-customext.cc b/ci-tests/test-customext.cc index acbb066..77c739f 100644 --- a/ci-tests/test-customext.cc +++ b/ci-tests/test-customext.cc @@ -26,11 +26,11 @@ static reg_t do_nop4([[maybe_unused]] processor_t *p, // dummy extension that uses the same prefix as standard zba extension struct xslliuw_dummy_t : public extension_t { - const char *name() { return "dummyslliuw"; } + const char *name() const { return "dummyslliuw"; } xslliuw_dummy_t() {} - std::vector<insn_desc_t> get_instructions() { + std::vector<insn_desc_t> get_instructions(const processor_t &) { std::vector<insn_desc_t> insns; insns.push_back(insn_desc_t{MATCH_SLLI_UW, MASK_SLLI_UW, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, do_nop4, @@ -38,7 +38,7 @@ struct xslliuw_dummy_t : public extension_t { return insns; } - std::vector<disasm_insn_t *> get_disasms() { + std::vector<disasm_insn_t *> get_disasms(const processor_t *) { std::vector<disasm_insn_t *> insns; insns.push_back(new disasm_insn_t("dummy_slliuw", MATCH_SLLI_UW, MASK_SLLI_UW, {&xrd, &xrs1, &shamt})); diff --git a/customext/cflush.cc b/customext/cflush.cc index 485716a..c090e88 100644 --- a/customext/cflush.cc +++ b/customext/cflush.cc @@ -19,23 +19,23 @@ static reg_t custom_cflush(processor_t* p, insn_t insn, reg_t pc) class cflush_t : public extension_t { public: - const char* name() { return "cflush"; } + const char* name() const override { return "cflush"; } cflush_t() {} - std::vector<insn_desc_t> get_instructions() { - std::vector<insn_desc_t> insns; - insns.push_back((insn_desc_t){0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); - insns.push_back((insn_desc_t){0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); - insns.push_back((insn_desc_t){0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}); + std::vector<insn_desc_t> get_instructions(const processor_t &) override { + std::vector<insn_desc_t> insns = { + {0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}, + {0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}, + {0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush}}; return insns; } - std::vector<disasm_insn_t*> get_disasms() { - std::vector<disasm_insn_t*> insns; - insns.push_back(new disasm_insn_t("cflush.d.l1", 0xFC000073, 0xFFF07FFF, {&xrs1})); - insns.push_back(new disasm_insn_t("cdiscard.d.l1", 0xFC200073, 0xFFF07FFF, {&xrs1})); - insns.push_back(new disasm_insn_t("cflush.i.l1", 0xFC100073, 0xFFF07FFF, {&xrs1})); + std::vector<disasm_insn_t *> get_disasms(const processor_t *) override { + std::vector<disasm_insn_t*> insns = { + new disasm_insn_t("cflush.d.l1", 0xFC000073, 0xFFF07FFF, {&xrs1}), + new disasm_insn_t("cdiscard.d.l1", 0xFC200073, 0xFFF07FFF, {&xrs1}), + new disasm_insn_t("cflush.i.l1", 0xFC100073, 0xFFF07FFF, {&xrs1})}; return insns; } }; diff --git a/customext/dummy_rocc.cc b/customext/dummy_rocc.cc index 8c051fa..6669887 100644 --- a/customext/dummy_rocc.cc +++ b/customext/dummy_rocc.cc @@ -5,14 +5,14 @@ class dummy_rocc_t : public rocc_t { public: - const char* name() { return "dummy_rocc"; } + const char* name() const { return "dummy_rocc"; } - reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t UNUSED xs2) + reg_t custom0(processor_t *p, rocc_insn_t insn, reg_t xs1, reg_t UNUSED xs2) { reg_t prev_acc = acc[insn.rs2]; if (insn.rs2 >= num_acc) - illegal_instruction(); + illegal_instruction(*p); switch (insn.funct) { @@ -28,7 +28,7 @@ class dummy_rocc_t : public rocc_t acc[insn.rs2] += xs1; break; default: - illegal_instruction(); + illegal_instruction(*p); } return prev_acc; // in all cases, xd <- previous value of acc[rs2] diff --git a/disasm/disasm.cc b/disasm/disasm.cc index 63fd12a..49f2794 100644 --- a/disasm/disasm.cc +++ b/disasm/disasm.cc @@ -706,26 +706,6 @@ static void NOINLINE add_sfence_insn(disassembler_t* d, const char* name, uint32 d->add_insn(new disasm_insn_t(name, match, mask, {&xrs1, &xrs2})); } -static void NOINLINE add_pitype3_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) -{ - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm3})); -} - -static void NOINLINE add_pitype4_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) -{ - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm4})); -} - -static void NOINLINE add_pitype5_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) -{ - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm5})); -} - -static void NOINLINE add_pitype6_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) -{ - d->add_insn(new disasm_insn_t(name, match, mask, {&xrd, &xrs1, &p_imm6})); -} - static void NOINLINE add_vector_v_insn(disassembler_t* d, const char* name, uint32_t match, uint32_t mask) { d->add_insn(new disasm_insn_t(name, match, mask, {&vd, &vs2, opt, &vm})); diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index bd2bbc9..baedc3f 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -1,11 +1,12 @@ #include "isa_parser.h" +#include <cstring> #include <stdexcept> static std::string strtolower(const char* str) { - std::string res; - for (const char *r = str; *r; r++) - res += std::tolower(*r); + std::string res(str); + for (char &c : res) + c = std::tolower(c); return res; } @@ -69,7 +70,7 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) // G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two // unconditionally, so they need not be explicitly added here. isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5); - // Fall through + [[fallthrough]]; case 'i': extension_table['I'] = true; break; @@ -97,9 +98,9 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) switch (*p) { case 'v': vlen = 128; elen = 64; zvf = true; zvd = true; - // even rv32iv implies double float + [[fallthrough]]; case 'q': extension_table['D'] = true; - // Fall through + [[fallthrough]]; case 'd': extension_table['F'] = true; } extension_table[toupper(*p)] = true; @@ -330,6 +331,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_SSCSRIND] = true; } else if (ext_str == "smcntrpmf") { extension_table[EXT_SMCNTRPMF] = true; + } else if (ext_str == "smcdeleg") { + extension_table[EXT_SMCDELEG] = true; + } else if (ext_str == "ssccfg") { + extension_table[EXT_SSCCFG] = true; } else if (ext_str == "zimop") { extension_table[EXT_ZIMOP] = true; } else if (ext_str == "zcmop") { diff --git a/fdt/fdt.mk.in b/fdt/fdt.mk.in index 64d06ac..accc080 100644 --- a/fdt/fdt.mk.in +++ b/fdt/fdt.mk.in @@ -16,4 +16,4 @@ fdt_c_srcs = \ fdt_addresses.c \ fdt_overlay.c \ -fdt_CFLAGS = -I$(src_dir)/fdt +fdt_CFLAGS = -I$(src_dir)/fdt -Wno-sign-compare diff --git a/fesvr/byteorder.h b/fesvr/byteorder.h index 71ce515..2147f96 100644 --- a/fesvr/byteorder.h +++ b/fesvr/byteorder.h @@ -16,8 +16,8 @@ static inline int32_t swap(int32_t n) { return int32_t(swap(uint32_t(n))); } static inline int64_t swap(int64_t n) { return int64_t(swap(uint64_t(n))); } #ifdef HAVE_INT128 -typedef __int128 int128_t; -typedef unsigned __int128 uint128_t; +__extension__ typedef __int128 int128_t; +__extension__ typedef unsigned __int128 uint128_t; static inline uint128_t swap(uint128_t n) { return (uint128_t(swap(uint64_t(n))) << 64) | swap(uint64_t(n >> 64)); } static inline int128_t swap(int128_t n) { return int128_t(swap(uint128_t(n))); } #endif diff --git a/fesvr/dtm.cc b/fesvr/dtm.cc index 0f810e7..a0c3254 100644 --- a/fesvr/dtm.cc +++ b/fesvr/dtm.cc @@ -51,6 +51,9 @@ } \ } +#define MAX_DATA_WORDS (1 << DM_ABSTRACTCS_DATACOUNT_LENGTH) +#define MAX_PROG_WORDS (1 << DM_ABSTRACTCS_PROGBUFSIZE_LENGTH) + uint32_t dtm_t::do_command(dtm_t::req r) { req_buf = r; @@ -61,17 +64,20 @@ uint32_t dtm_t::do_command(dtm_t::req r) uint32_t dtm_t::read(uint32_t addr) { - return do_command((req){addr, 1, 0}); + req r = {addr, 1, 0}; + return do_command(r); } uint32_t dtm_t::write(uint32_t addr, uint32_t data) { - return do_command((req){addr, 2, data}); + req r = {addr, 2, data}; + return do_command(r); } void dtm_t::nop() { - do_command((req){0, 0, 0}); + req r = {0, 0, 0}; + do_command(r); } void dtm_t::select_hart(int hartsel) { @@ -104,7 +110,7 @@ void dtm_t::halt(int hartsel) read(DM_DMSTATUS); } - int dmcontrol = DM_DMCONTROL_HALTREQ | DM_DMCONTROL_DMACTIVE; + reg_t dmcontrol = DM_DMCONTROL_HALTREQ | DM_DMCONTROL_DMACTIVE; dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, hartsel); write(DM_DMCONTROL, dmcontrol); int dmstatus; @@ -142,7 +148,7 @@ void dtm_t::resume(int hartsel) uint64_t dtm_t::save_reg(unsigned regno) { - uint32_t data[xlen/(8*4)]; + uint32_t data[MAX_DATA_WORDS]; uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno); RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4)); @@ -155,7 +161,7 @@ uint64_t dtm_t::save_reg(unsigned regno) void dtm_t::restore_reg(unsigned regno, uint64_t val) { - uint32_t data[xlen/(8*4)]; + uint32_t data[MAX_DATA_WORDS]; data[0] = (uint32_t) val; if (xlen > 32) { data[1] = (uint32_t) (val >> 32); @@ -174,8 +180,8 @@ uint32_t dtm_t::run_abstract_command(uint32_t command, const uint32_t program[], size_t program_n, uint32_t data[], size_t data_n) { - assert(program_n <= ram_words); - assert(data_n <= data_words); + assert(program_n <= MAX_PROG_WORDS); + assert(data_n <= MAX_DATA_WORDS); for (size_t i = 0; i < program_n; i++) { write(DM_PROGBUF0 + i, program[i]); @@ -214,8 +220,8 @@ size_t dtm_t::chunk_align() void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; uint8_t * curr = (uint8_t*) dst; @@ -267,8 +273,8 @@ void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst) void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; const uint8_t * curr = (const uint8_t*) src; @@ -362,8 +368,8 @@ void dtm_t::die(uint32_t cmderr) void dtm_t::clear_chunk(uint64_t taddr, size_t len) { - uint32_t prog[ram_words]; - uint32_t data[data_words]; + uint32_t prog[MAX_PROG_WORDS]; + uint32_t data[MAX_DATA_WORDS]; halt(current_hart); uint64_t s0 = save_reg(S0); @@ -477,8 +483,8 @@ uint32_t dtm_t::get_xlen() uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0); uint32_t cmderr; - const uint32_t prog[] = {}; - uint32_t data[] = {}; + const uint32_t prog[1] = {}; + uint32_t data[1] = {}; cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0); if (cmderr == 0){ @@ -560,11 +566,6 @@ void dtm_t::producer_thread() // Poll until the debugger agrees it's enabled. while ((read(DM_DMCONTROL) & DM_DMCONTROL_DMACTIVE) == 0) ; - // These are checked every time we run an abstract command. - uint32_t abstractcs = read(DM_ABSTRACTCS); - ram_words = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); - data_words = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); - // These things are only needed for the 'modify_csr' function. // That could be re-written to not use these at some performance // overhead. diff --git a/fesvr/dtm.h b/fesvr/dtm.h index f47b648..03c2f79 100644 --- a/fesvr/dtm.h +++ b/fesvr/dtm.h @@ -109,8 +109,6 @@ class dtm_t : public htif_t static const int max_idle_cycles = 10000; - size_t ram_words; - size_t data_words; int num_harts; int current_hart; diff --git a/fesvr/htif.cc b/fesvr/htif.cc index a2477c1..15f79bf 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -65,14 +65,14 @@ htif_t::htif_t(int argc, char** argv) : htif_t() htif_t::htif_t(const std::vector<std::string>& args) : htif_t() { int argc = args.size() + 1; - char * argv[argc]; + std::vector<char*>argv(argc); argv[0] = (char *) "htif"; for (unsigned int i = 0; i < args.size(); i++) { argv[i+1] = (char *) args[i].c_str(); } //Set line size as 16 by default. line_size = 16; - parse_arguments(argc, argv); + parse_arguments(argc, &argv[0]); register_devices(); } @@ -158,11 +158,9 @@ void htif_t::load_symbols(std::map<std::string, uint64_t>& symbols) { class nop_memif_t : public memif_t { public: - nop_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {} + nop_memif_t(htif_t* htif) : memif_t(htif) {} void read(addr_t UNUSED addr, size_t UNUSED len, void UNUSED *bytes) override {} void write(addr_t UNUSED taddr, size_t UNUSED len, const void UNUSED *src) override {} - private: - htif_t* htif; } nop_memif(this); reg_t nop_entry; @@ -253,11 +251,10 @@ void htif_t::stop() void htif_t::clear_chunk(addr_t taddr, size_t len) { - char zeros[chunk_max_size()]; - memset(zeros, 0, chunk_max_size()); + std::vector<uint8_t> zeros(chunk_max_size(), 0); for (size_t pos = 0; pos < len; pos += chunk_max_size()) - write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), zeros); + write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), &zeros[0]); } int htif_t::run() diff --git a/fesvr/memif.cc b/fesvr/memif.cc index e56bd94..59938b9 100644 --- a/fesvr/memif.cc +++ b/fesvr/memif.cc @@ -12,10 +12,10 @@ void memif_t::read(addr_t addr, size_t len, void* bytes) if (len && (addr & (align-1))) { size_t this_len = std::min(len, align - size_t(addr & (align-1))); - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr & ~(align-1), align, chunk); - memcpy(bytes, chunk + (addr & (align-1)), this_len); + cmemif->read_chunk(addr & ~(align-1), align, &chunk[0]); + memcpy(bytes, &chunk[addr & (align-1)], this_len); bytes = (char*)bytes + this_len; addr += this_len; @@ -26,10 +26,10 @@ void memif_t::read(addr_t addr, size_t len, void* bytes) { size_t this_len = len & (align-1); size_t start = len - this_len; - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr + start, align, chunk); - memcpy((char*)bytes + start, chunk, this_len); + cmemif->read_chunk(addr + start, align, &chunk[0]); + memcpy((char*)bytes + start, &chunk[0], this_len); len -= this_len; } @@ -45,11 +45,11 @@ void memif_t::write(addr_t addr, size_t len, const void* bytes) if (len && (addr & (align-1))) { size_t this_len = std::min(len, align - size_t(addr & (align-1))); - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr & ~(align-1), align, chunk); - memcpy(chunk + (addr & (align-1)), bytes, this_len); - cmemif->write_chunk(addr & ~(align-1), align, chunk); + cmemif->read_chunk(addr & ~(align-1), align, &chunk[0]); + memcpy(&chunk[addr & (align-1)], bytes, this_len); + cmemif->write_chunk(addr & ~(align-1), align, &chunk[0]); bytes = (char*)bytes + this_len; addr += this_len; @@ -60,11 +60,11 @@ void memif_t::write(addr_t addr, size_t len, const void* bytes) { size_t this_len = len & (align-1); size_t start = len - this_len; - uint8_t chunk[align]; + std::vector<uint8_t> chunk(align); - cmemif->read_chunk(addr + start, align, chunk); - memcpy(chunk, (char*)bytes + start, this_len); - cmemif->write_chunk(addr + start, align, chunk); + cmemif->read_chunk(addr + start, align, &chunk[0]); + memcpy(&chunk[0], (char*)bytes + start, this_len); + cmemif->write_chunk(addr + start, align, &chunk[0]); len -= this_len; } diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index f848126..014a468 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -114,19 +114,23 @@ struct riscv_statx attributes_mask(htif->to_target<uint64_t>(s.stx_attributes_mask)), atime { htif->to_target<int64_t>(s.stx_atime.tv_sec), - htif->to_target<uint32_t>(s.stx_atime.tv_nsec) + htif->to_target<uint32_t>(s.stx_atime.tv_nsec), + htif->to_target<int32_t>(0) }, btime { htif->to_target<int64_t>(s.stx_btime.tv_sec), - htif->to_target<uint32_t>(s.stx_btime.tv_nsec) + htif->to_target<uint32_t>(s.stx_btime.tv_nsec), + htif->to_target<int32_t>(0) }, ctime { htif->to_target<int64_t>(s.stx_ctime.tv_sec), - htif->to_target<uint32_t>(s.stx_ctime.tv_nsec) + htif->to_target<uint32_t>(s.stx_ctime.tv_nsec), + htif->to_target<int32_t>(0) }, mtime { htif->to_target<int64_t>(s.stx_mtime.tv_sec), - htif->to_target<uint32_t>(s.stx_mtime.tv_nsec) + htif->to_target<uint32_t>(s.stx_mtime.tv_nsec), + htif->to_target<int32_t>(0) }, rdev_major(htif->to_target<uint32_t>(s.stx_rdev_major)), rdev_minor(htif->to_target<uint32_t>(s.stx_rdev_minor)), diff --git a/riscv/abstract_device.h b/riscv/abstract_device.h index 0726cd7..d8ddbab 100644 --- a/riscv/abstract_device.h +++ b/riscv/abstract_device.h @@ -16,6 +16,7 @@ class abstract_device_t { public: virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0; virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0; + virtual reg_t size() = 0; virtual ~abstract_device_t() {} virtual void tick(reg_t UNUSED rtc_ticks) {} }; diff --git a/riscv/cfg.h b/riscv/cfg.h index c972f03..388030b 100644 --- a/riscv/cfg.h +++ b/riscv/cfg.h @@ -6,6 +6,7 @@ #include <vector> #include "decode.h" #include <cassert> +class abstract_sim_if_t; typedef enum { endianness_little, @@ -77,6 +78,7 @@ public: bool explicit_hartids; bool real_time_clint; reg_t trigger_count; + std::optional<abstract_sim_if_t*> external_simulator; size_t nprocs() const { return hartids.size(); } size_t max_hartid() const { return hartids.back(); } diff --git a/riscv/clint.cc b/riscv/clint.cc index 208ea0e..3d5c984 100644 --- a/riscv/clint.cc +++ b/riscv/clint.cc @@ -39,7 +39,8 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes) tick(0); - if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + static_assert(MSIP_BASE == 0); + if (/* addr >= MSIP_BASE && */ addr < MTIMECMP_BASE) { if (len == 8) { // Implement double-word loads as a pair of word loads return load(addr, 4, bytes) && load(addr + 4, 4, bytes + 4); @@ -68,7 +69,8 @@ bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes) if (len > 8) return false; - if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) { + static_assert(MSIP_BASE == 0); + if (/* addr >= MSIP_BASE && */ addr < MTIMECMP_BASE) { if (len == 8) { // Implement double-word stores as a pair of word stores return store(addr, 4, bytes) && store(addr + 4, 4, bytes + 4); @@ -117,7 +119,7 @@ void clint_t::tick(reg_t rtc_ticks) } clint_t* clint_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, - const std::vector<std::string>& UNUSED sargs) { + const std::vector<std::string>& sargs UNUSED) { if (fdt_parse_clint(fdt, base, "riscv,clint0") == 0 || fdt_parse_clint(fdt, base, "sifive,clint0") == 0) return new clint_t(sim, sim->CPU_HZ / sim->INSNS_PER_RTC_TICK, @@ -126,7 +128,7 @@ clint_t* clint_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, return nullptr; } -std::string clint_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) { +std::string clint_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex << " clint@" << CLINT_BASE << " {\n" diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index a03d188..cabb7c2 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -250,7 +250,8 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0) | (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0) | (proc->extension_enabled(EXT_ZICFISS) ? MENVCFG_SSE : 0) | - (proc->extension_enabled(EXT_SSDBLTRP) ? MENVCFG_DTE : 0); + (proc->extension_enabled(EXT_SSDBLTRP) ? MENVCFG_DTE : 0)| + (proc->extension_enabled(EXT_SMCSRIND) ? MENVCFG_CDE : 0); menvcfg = std::make_shared<envcfg_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, 0); if (xlen == 32) { add_user_csr(CSR_MENVCFG, std::make_shared<rv32_low_csr_t>(proc, CSR_MENVCFG, menvcfg)); @@ -337,6 +338,10 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) const reg_t ssp_mask = -reg_t(xlen / 8); add_ext_csr(EXT_ZICFISS, CSR_SSP, ssp = std::make_shared<ssp_csr_t>(proc, CSR_SSP, ssp_mask, 0)); + // Smcdeleg + if (proc->extension_enabled_const(EXT_SMCDELEG) || proc->extension_enabled_const(EXT_SSCCFG)) { + add_supervisor_csr(CSR_SCOUNTINHIBIT, scountinhibit = std::make_shared<scntinhibit_csr_t>(proc, CSR_SCOUNTINHIBIT, mcountinhibit)); + } // Smcsrind / Sscsrind if (proc->extension_enabled_const(EXT_SMCSRIND)) { @@ -363,6 +368,59 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) auto sireg = std::make_shared<sscsrind_reg_csr_t>(proc, sireg_csrs[i], siselect); add_supervisor_csr(sireg_csrs[i], std::make_shared<virtualized_indirect_csr_t>(proc, sireg, vsireg)); + + // Smcdeleg + if (proc->extension_enabled(EXT_SSCCFG) || proc->extension_enabled(EXT_SMCDELEG)) { + switch (sireg_csrs[i]) { + case CSR_SIREG: + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcycle); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, minstret); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3 + j]); + } + break; + case CSR_SIREG4: + if (xlen == 32) { + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, csrmap[CSR_CYCLEH]); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, csrmap[CSR_INSTRETH]); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3H + j]); + } + } + break; + case CSR_SIREG2: + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcyclecfg); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRETCFG, minstretcfg); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3 + 1); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMEVENT_3 + j, csrmap[CSR_MHPMEVENT3H + j]); + } + break; + case CSR_SIREG5: + if (xlen == 32) { + if (proc->extension_enabled_const(EXT_ZICNTR)) { + sireg->add_ireg_proxy(SISELECT_SMCDELEG_START, mcycle); + sireg->add_ireg_proxy(SISELECT_SMCDELEG_INSTRET, minstret); + } + if (proc->extension_enabled_const(EXT_ZIHPM)) { + for (size_t j = 0; j < (SISELECT_SMCDELEG_END - SISELECT_SMCDELEG_HPMEVENT_3); j++) + sireg->add_ireg_proxy(SISELECT_SMCDELEG_HPMCOUNTER_3 + j, csrmap[CSR_HPMCOUNTER3 + j]); + } + } + case CSR_SIREG3: + case CSR_SIREG6: + default: + break; + } + } } } diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 3dbac7b..1873f7e 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1075,6 +1075,7 @@ bool virtualized_satp_csr_t::unlogged_write(const reg_t val) noexcept { wide_counter_csr_t::wide_counter_csr_t(processor_t* const proc, const reg_t addr, smcntrpmf_csr_t_p config_csr): csr_t(proc, addr), val(0), + written(false), config_csr(config_csr) { } @@ -1083,7 +1084,15 @@ reg_t wide_counter_csr_t::read() const noexcept { } void wide_counter_csr_t::bump(const reg_t howmuch) noexcept { - if (is_counting_enabled()) { + if (written) { + // Because writing a CSR serializes the simulator, howmuch should + // reflect exactly one instruction: the explicit CSR write. + // If counting is disabled, though, howmuch will be zero. + assert(howmuch <= 1); + // The ISA mandates that explicit writes to instret take precedence + // over the instret, so simply skip the increment. + written = false; + } else if (is_counting_enabled()) { val += howmuch; // to keep log reasonable size, don't log every bump } // Clear cached value @@ -1091,23 +1100,15 @@ void wide_counter_csr_t::bump(const reg_t howmuch) noexcept { } bool wide_counter_csr_t::unlogged_write(const reg_t val) noexcept { + // Because writing a CSR serializes the simulator and is followed by a + // bump, back-to-back writes with no intervening bump should never occur. + assert(!written); + written = true; + this->val = val; - // The ISA mandates that if an instruction writes instret, the write - // takes precedence over the increment to instret. However, Spike - // unconditionally increments instret after executing an instruction. - // Correct for this artifact by decrementing instret here. - // Ensure that Smctrpmf hasn't disabled counting. - if (is_counting_enabled()) { - this->val--; - } return true; } -reg_t wide_counter_csr_t::written_value() const noexcept { - // Re-adjust for upcoming bump() - return this->val + 1; -} - // Returns true if counting is not inhibited by Smcntrpmf. // Note that minstretcfg / mcyclecfg / mhpmevent* share the same inhibit bits. bool wide_counter_csr_t::is_counting_enabled() const noexcept { @@ -1230,7 +1231,7 @@ hideleg_csr_t::hideleg_csr_t(processor_t* const proc, const reg_t addr, csr_t_p reg_t hideleg_csr_t::read() const noexcept { return masked_csr_t::read() & mideleg->read(); -}; +} hgatp_csr_t::hgatp_csr_t(processor_t* const proc, const reg_t addr): basic_csr_t(proc, addr, 0) { @@ -1676,6 +1677,14 @@ scountovf_csr_t::scountovf_csr_t(processor_t* const proc, const reg_t addr): void scountovf_csr_t::verify_permissions(insn_t insn, bool write) const { if (!proc->extension_enabled(EXT_SSCOFPMF)) throw trap_illegal_instruction(insn.bits()); + + if (proc->extension_enabled('H') && + (proc->extension_enabled_const(EXT_SMCDELEG) || proc->extension_enabled(EXT_SSCCFG)) + ) { + if (state->v && (state->menvcfg->read() & MENVCFG_CDE)) { + throw trap_virtual_instruction(insn.bits()); + } + } csr_t::verify_permissions(insn, write); } @@ -1749,6 +1758,68 @@ void sscsrind_reg_csr_t::verify_permissions(insn_t insn, bool write) const { if (insn.csr() == address) csr_t::verify_permissions(insn, write); + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_CSRIND)) + throw trap_virtual_instruction(insn.bits()); + } + + if (proc->extension_enabled(EXT_SMCDELEG)) { + if (insn.csr() >= CSR_VSIREG && insn.csr() <= CSR_VSIREG6) { + if (!state->v) { + // An attempt to access any vsireg* from M or S mode raises an illegal instruction exception. + throw trap_illegal_instruction(insn.bits()); + } else { + if (state->prv == PRV_S) { + // An attempt from VS-mode to access any vsireg raises an illegal instruction + // exception if menvcfg.CDE = 0, or a virtual instruction exception if menvcfg.CDE = 1 + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } + if (insn.csr() >= CSR_SIREG && insn.csr() <= CSR_SIREG6) { + // attempts to access any sireg* when menvcfg.CDE = 0; + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + if (!state->v) { + throw trap_illegal_instruction(insn.bits()); + } else { + if (state->prv == PRV_S) { + // An attempt from VS-mode to access any sireg* causes illegal instruction exception if menvcfg.CDE = 0 + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } else { + // menvcfg.CDE = 1; + if (state->v) { + // An attempt from VS-mode to access any sireg* causes a virtual instruction exception if menvcfg.CDE = 1 + throw trap_virtual_instruction(insn.bits()); + } + // counter selected by siselect is not delegated to S-mode (the corresponding bit in mcounteren = 0). + auto iselect_addr = iselect->read(); + if (iselect_addr >= SISELECT_SMCDELEG_START && iselect_addr <= SISELECT_SMCDELEG_END) { + reg_t counter_id_offset = iselect_addr - SISELECT_SMCDELEG_START; + if (!(state->mcounteren->read() & (1U << counter_id_offset))) { + if (!state->v) { + throw trap_illegal_instruction(insn.bits()); + } else { + throw trap_virtual_instruction(insn.bits()); + } + } + } + } + } + } + csr_t_p proxy_csr = get_reg(); if (proxy_csr == nullptr) { if (!state->v) { @@ -1810,7 +1881,7 @@ srmcfg_csr_t::srmcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_ masked_csr_t(proc, addr, mask, init) { } -void srmcfg_csr_t::verify_permissions(insn_t insn, bool write) const { +void srmcfg_csr_t::verify_permissions(insn_t insn, bool write UNUSED) const { if (!proc->extension_enabled(EXT_SSQOSID)) throw trap_illegal_instruction(insn.bits()); @@ -1879,3 +1950,26 @@ bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept { proc->get_mmu()->flush_tlb(); return basic_csr_t::unlogged_write(new_hstatus); } + +scntinhibit_csr_t::scntinhibit_csr_t(processor_t* const proc, const reg_t addr, csr_t_p mcountinhibit): + basic_csr_t(proc, addr, mcountinhibit->read()) { +} + +void scntinhibit_csr_t::verify_permissions(insn_t insn, bool write) const { + if (insn.csr() == address) { + csr_t::verify_permissions(insn, write); + } + + if ((state->menvcfg->read() & MENVCFG_CDE) != MENVCFG_CDE) { + throw trap_illegal_instruction(insn.bits()); + } +} + +bool scntinhibit_csr_t::unlogged_write(const reg_t val) noexcept { + state->mcountinhibit->write(state->mcounteren->read() & val); + return true; +} + +reg_t scntinhibit_csr_t::read() const noexcept { + return state->mcounteren->read() & state->mcountinhibit->read(); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 278bdb3..33ac33e 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -542,10 +542,10 @@ class wide_counter_csr_t: public csr_t { void bump(const reg_t howmuch) noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; - virtual reg_t written_value() const noexcept override; private: bool is_counting_enabled() const noexcept; reg_t val; + bool written; smcntrpmf_csr_t_p config_csr; }; @@ -899,4 +899,14 @@ class hstatus_csr_t final: public basic_csr_t { protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; + +class scntinhibit_csr_t: public basic_csr_t { + public: + scntinhibit_csr_t(processor_t* const proc, const reg_t addr, csr_t_p mcountinhibit); + reg_t read() const noexcept override; + virtual void verify_permissions(insn_t insn, bool write) const override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + #endif diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 7c59744..a89a4ff 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -13,7 +13,7 @@ #if 0 # define D(x) x #else -# define D(x) +# define D(x) (void) 0 #endif // Return the number of bits wide that a field has to be to encode up to n @@ -249,6 +249,11 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } +reg_t debug_module_t::size() +{ + return PGSIZE; +} + void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value) { uint8_t* base = memory + index * 4; @@ -445,7 +450,6 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) } else { dmstatus.allresumeack = false; } - auto hart = sim->get_harts().at(hart_id); if (!hart_available(hart_id)) { dmstatus.allrunning = false; dmstatus.allhalted = false; diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 3771489..904f03e 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -114,8 +114,9 @@ class debug_module_t : public abstract_device_t debug_module_t(simif_t *sim, const debug_module_config_t &config); ~debug_module_t(); - bool load(reg_t addr, size_t len, uint8_t* bytes); - bool store(reg_t addr, size_t len, const uint8_t* bytes); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; // Debug Module Interface that the debugger (in our case through JTAG DTM) // uses to access the DM. diff --git a/riscv/decode.h b/riscv/decode.h index f36c04e..d17cb6b 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -170,23 +170,29 @@ public: switch (rvc_rlist()) { case 15: stack_adj_base += 16; + [[fallthrough]]; case 14: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 13: case 12: stack_adj_base += 16; + [[fallthrough]]; case 11: case 10: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 9: case 8: stack_adj_base += 16; + [[fallthrough]]; case 7: case 6: if (xlen == 64) stack_adj_base += 16; + [[fallthrough]]; case 5: case 4: stack_adj_base += 16; diff --git a/riscv/decode_macros.h b/riscv/decode_macros.h index 807ad98..892515f 100644 --- a/riscv/decode_macros.h +++ b/riscv/decode_macros.h @@ -337,10 +337,10 @@ inline long double to_f(float128_t f) { long double r; memcpy(&r, &f, sizeof(r)) #define DEBUG_RVV_FMA_VF \ printf("vfma(%lu) vd=%f vs1=%f vs2=%f vd_old=%f\n", i, to_f(vd), to_f(rs1), to_f(vs2), to_f(vd_old)); #else -#define DEBUG_RVV_FP_VV 0 -#define DEBUG_RVV_FP_VF 0 -#define DEBUG_RVV_FMA_VV 0 -#define DEBUG_RVV_FMA_VF 0 +#define DEBUG_RVV_FP_VV (void) 0 +#define DEBUG_RVV_FP_VF (void) 0 +#define DEBUG_RVV_FMA_VV (void) 0 +#define DEBUG_RVV_FMA_VF (void) 0 #endif #define DECLARE_XENVCFG_VARS(field) \ diff --git a/riscv/devices.cc b/riscv/devices.cc index 2c06f78..fb5bb5a 100644 --- a/riscv/devices.cc +++ b/riscv/devices.cc @@ -8,53 +8,92 @@ mmio_device_map_t& mmio_device_map() return device_map; } +static auto empty_device = rom_device_t(std::vector<char>()); + +bus_t::bus_t() + : bus_t(&empty_device) +{ +} + +bus_t::bus_t(abstract_device_t* fallback) + : fallback(fallback) +{ +} + void bus_t::add_device(reg_t addr, abstract_device_t* dev) { - // Searching devices via lower_bound/upper_bound - // implicitly relies on the underlying std::map - // container to sort the keys and provide ordered - // iteration over this sort, which it does. (python's - // SortedDict is a good analogy) + // Allow empty devices by omitting them + auto size = dev->size(); + if (size == 0) + return; + + // Reject devices that overflow address size + if (addr + size - 1 < addr) { + fprintf(stderr, "device at [%" PRIx64 ", %" PRIx64 ") overflows address size\n", + addr, addr + size); + abort(); + } + + // Reject devices that overlap other devices + if (auto it = devices.upper_bound(addr); + (it != devices.end() && addr + size - 1 >= it->first) || + (it != devices.begin() && (it--, it->first + it->second->size() - 1 >= addr))) { + fprintf(stderr, "devices at [%" PRIx64 ", %" PRIx64 ") and [%" PRIx64 ", %" PRIx64 ") overlap\n", + it->first, it->first + it->second->size(), addr, addr + size); + abort(); + } + devices[addr] = dev; } bool bus_t::load(reg_t addr, size_t len, uint8_t* bytes) { - // Find the device with the base address closest to but - // less than addr (price-is-right search) - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - // Either the bus is empty, or there weren't - // any items with a base address <= addr - return false; - } - // Found at least one item with base address <= addr - // The iterator points to the device after this, so - // go back by one item. - it--; - return it->second->load(addr - it->first, len, bytes); + if (auto [base, dev] = find_device(addr, len); dev) + return dev->load(addr - base, len, bytes); + return false; } bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes) { - // See comments in bus_t::load - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - return false; - } - it--; - return it->second->store(addr - it->first, len, bytes); + if (auto [base, dev] = find_device(addr, len); dev) + return dev->store(addr - base, len, bytes); + return false; } -std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr) +reg_t bus_t::size() { - // See comments in bus_t::load - auto it = devices.upper_bound(addr); - if (devices.empty() || it == devices.begin()) { - return std::make_pair((reg_t)0, (abstract_device_t*)NULL); + if (auto last = devices.rbegin(); last != devices.rend()) + return last->first + last->second->size(); + return 0; +} + +std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr, size_t len) +{ + if (unlikely(!len || addr + len - 1 < addr)) + return std::make_pair(0, nullptr); + + // Obtain iterator to device immediately after the one that might match + auto it_after = devices.upper_bound(addr); + reg_t base, size; + if (likely(it_after != devices.begin())) { + // Obtain iterator to device that might match + auto it = std::prev(it_after); + base = it->first; + size = it->second->size(); + if (likely(addr - base + len - 1 < size)) { + // it fully contains [addr, addr + len) + return std::make_pair(it->first, it->second); + } } - it--; - return std::make_pair(it->first, it->second); + + if (unlikely((it_after != devices.end() && addr + len - 1 >= it_after->first) + || (it_after != devices.begin() && addr - base < size))) { + // it_after or it contains part of, but not all of, [addr, add + len) + return std::make_pair(0, nullptr); + } + + // No matching device + return std::make_pair(0, fallback); } mem_t::mem_t(reg_t size) @@ -116,3 +155,25 @@ void mem_t::dump(std::ostream& o) { } } } + +external_sim_device_t::external_sim_device_t(void* sim) + : external_simulator(sim) {} + +void external_sim_device_t::set_simulator(void* sim) { + external_simulator = sim; +} + +bool external_sim_device_t::load(reg_t addr, size_t len, uint8_t* bytes) { + if (unlikely(external_simulator == nullptr)) return false; + return static_cast<abstract_sim_if_t*>(external_simulator)->load(addr, len, bytes); +} + +bool external_sim_device_t::store(reg_t addr, size_t len, const uint8_t* bytes) { + if (unlikely(external_simulator == nullptr)) return false; + return static_cast<abstract_sim_if_t*>(external_simulator)->store(addr, len, bytes); +} + +reg_t external_sim_device_t::size() { + if (unlikely(external_simulator == nullptr)) return 0; + return PGSIZE; // TODO: proper size +} diff --git a/riscv/devices.h b/riscv/devices.h index 6ef32e9..e7b80ad 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -16,14 +16,21 @@ class simif_t; class bus_t : public abstract_device_t { public: + bus_t(); + + // the fallback device owns all addresses not owned by other devices + bus_t(abstract_device_t* fallback); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; void add_device(reg_t addr, abstract_device_t* dev); - std::pair<reg_t, abstract_device_t*> find_device(reg_t addr); + std::pair<reg_t, abstract_device_t*> find_device(reg_t addr, size_t len); private: std::map<reg_t, abstract_device_t*> devices; + abstract_device_t* fallback; }; class rom_device_t : public abstract_device_t { @@ -31,6 +38,7 @@ class rom_device_t : public abstract_device_t { rom_device_t(std::vector<char> data); bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override { return data.size(); } const std::vector<char>& contents() { return data; } private: std::vector<char> data; @@ -41,7 +49,6 @@ class abstract_mem_t : public abstract_device_t { virtual ~abstract_mem_t() = default; virtual char* contents(reg_t addr) = 0; - virtual reg_t size() = 0; virtual void dump(std::ostream& o) = 0; }; @@ -64,12 +71,31 @@ class mem_t : public abstract_mem_t { reg_t sz; }; +class abstract_sim_if_t { +public: + virtual ~abstract_sim_if_t() = default; + virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0; + virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0; +}; + +class external_sim_device_t : public abstract_device_t { +public: + external_sim_device_t(void* sim); + void set_simulator(void* sim); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; + +private: + void* external_simulator; +}; + class clint_t : public abstract_device_t { public: clint_t(const simif_t*, uint64_t freq_hz, bool real_time); bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; - size_t size() { return CLINT_SIZE; } + reg_t size() override { return CLINT_SIZE; } void tick(reg_t rtc_ticks) override; uint64_t get_mtimecmp(reg_t hartid) { return mtimecmp[hartid]; } uint64_t get_mtime() { return mtime; } @@ -109,7 +135,7 @@ class plic_t : public abstract_device_t, public abstract_interrupt_controller_t bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; void set_interrupt_level(uint32_t id, int lvl) override; - size_t size() { return PLIC_SIZE; } + reg_t size() override { return PLIC_SIZE; } private: std::vector<plic_context_t> contexts; uint32_t num_ids; @@ -140,7 +166,7 @@ class ns16550_t : public abstract_device_t { bool load(reg_t addr, size_t len, uint8_t* bytes) override; bool store(reg_t addr, size_t len, const uint8_t* bytes) override; void tick(reg_t rtc_ticks) override; - size_t size() { return NS16550_SIZE; } + reg_t size() override { return NS16550_SIZE; } private: abstract_interrupt_controller_t *intctrl; uint32_t interrupt_id; diff --git a/riscv/dts.cc b/riscv/dts.cc index 9751ffe..5be9d57 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -424,7 +424,6 @@ int fdt_parse_isa(const void *fdt, int cpu_offset, const char **isa) 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) diff --git a/riscv/execute.cc b/riscv/execute.cc index 1fa6111..c29eb2d 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -40,13 +40,12 @@ static void commit_log_print_value(FILE *log_file, int width, const void *data) fprintf(log_file, "0x%016" PRIx64, *(const uint64_t *)data); break; default: - // max lengh of vector - if (((width - 1) & width) == 0) { - const uint64_t *arr = (const uint64_t *)data; + if (width % 8 == 0) { + const uint8_t *arr = (const uint8_t *)data; fprintf(log_file, "0x"); - for (int idx = width / 64 - 1; idx >= 0; --idx) { - fprintf(log_file, "%016" PRIx64, arr[idx]); + for (int idx = width / 8 - 1; idx >= 0; --idx) { + fprintf(log_file, "%02" PRIx8, arr[idx]); } } else { abort(); @@ -365,12 +364,10 @@ void processor_t::step(size_t n) in_wfi = true; } - if (!(state.mcountinhibit->read() & MCOUNTINHIBIT_IR)) - state.minstret->bump(instret); + state.minstret->bump((state.mcountinhibit->read() & MCOUNTINHIBIT_IR) ? 0 : instret); // Model a hart whose CPI is 1. - if (!(state.mcountinhibit->read() & MCOUNTINHIBIT_CY)) - state.mcycle->bump(instret); + state.mcycle->bump((state.mcountinhibit->read() & MCOUNTINHIBIT_CY) ? 0 : instret); n -= instret; } diff --git a/riscv/extension.cc b/riscv/extension.cc index 520c2ed..195eea1 100644 --- a/riscv/extension.cc +++ b/riscv/extension.cc @@ -3,21 +3,15 @@ #include "extension.h" #include "trap.h" -extension_t::~extension_t() -{ -} - -void extension_t::illegal_instruction() +void extension_t::illegal_instruction([[maybe_unused]] processor_t &proc) { throw trap_illegal_instruction(0); } -void extension_t::raise_interrupt() +void extension_t::raise_interrupt([[maybe_unused]] processor_t &proc) { - p->take_interrupt((reg_t)1 << IRQ_COP); // must not return + proc.take_interrupt((reg_t)1 << IRQ_COP); // must not return throw std::logic_error("a COP exception was posted, but interrupts are disabled!"); } -void extension_t::clear_interrupt() -{ -} +void extension_t::clear_interrupt([[maybe_unused]] processor_t &proc) {} diff --git a/riscv/extension.h b/riscv/extension.h index 991da7e..411e65b 100644 --- a/riscv/extension.h +++ b/riscv/extension.h @@ -11,21 +11,18 @@ class extension_t { public: - virtual std::vector<insn_desc_t> get_instructions() = 0; - virtual std::vector<disasm_insn_t*> get_disasms() = 0; - virtual std::vector<csr_t_p> get_csrs ([[maybe_unused]] processor_t &proc) const { return {}; }; - virtual const char* name() = 0; - virtual void reset() {}; - virtual void set_debug(bool UNUSED value) {} - virtual ~extension_t(); + virtual std::vector<insn_desc_t> get_instructions(const processor_t &proc) = 0; + virtual std::vector<disasm_insn_t*> get_disasms(const processor_t *proc = nullptr) = 0; + virtual std::vector<csr_t_p> get_csrs(processor_t &) const { return {}; }; + virtual const char* name() const = 0; + virtual void reset(processor_t &) {}; + virtual void set_debug(bool UNUSED value, const processor_t &) {} + virtual ~extension_t() = default; - void set_processor(processor_t* _p) { p = _p; } protected: - processor_t* p; - - void illegal_instruction(); - void raise_interrupt(); - void clear_interrupt(); + void illegal_instruction(processor_t &proc); + void raise_interrupt(processor_t &proc); + void clear_interrupt(processor_t &proc); }; std::function<extension_t*()> find_extension(const char* name); diff --git a/riscv/interactive.cc b/riscv/interactive.cc index 2701f49..9afc718 100644 --- a/riscv/interactive.cc +++ b/riscv/interactive.cc @@ -83,8 +83,7 @@ static void clear_str(bool noncanonical, int fd, std::string target_str) clear_motion += ' '; } clear_motion += '\r'; - if (write(fd, clear_motion.c_str(), clear_motion.size() + 1)) - ; // shut up gcc + (void) write(fd, clear_motion.c_str(), clear_motion.size() + 1); } } @@ -97,8 +96,7 @@ static void send_key(bool noncanonical, int fd, keybuffer_t key_code, const int { key_motion += (char) ((key_code >> (i * BITS_PER_CHAR)) & 0xff); } - if (write(fd, key_motion.c_str(), len) != len) - ; // shut up gcc + (void) write(fd, key_motion.c_str(), len); } } @@ -145,8 +143,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); cursor_pos--; s.erase(cursor_pos, 1); - if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); // move cursor by left arrow key for (unsigned i = 0; i < s.size() - cursor_pos; i++) { send_key(noncanonical, fd, KEYCODE_LEFT, 3); @@ -177,8 +175,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); history_index = std::min(history_commands.size(), history_index + 1); s = history_commands[history_commands.size() - history_index]; - if (noncanonical && write(fd, s.c_str(), s.size() + 1)) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); cursor_pos = s.size(); } key_buffer = 0; @@ -193,8 +191,8 @@ static std::string readline(int fd) } else { s = history_commands[history_commands.size() - history_index]; } - if (noncanonical && write(fd, s.c_str(), s.size() + 1)) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); cursor_pos = s.size(); } key_buffer = 0; @@ -222,14 +220,13 @@ static std::string readline(int fd) key_buffer = 0; break; case KEYCODE_ENTER: - if (noncanonical && write(fd, &ch, 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, &ch, 1); if (s.size() > initial_s_len && (history_commands.size() == 0 || s != history_commands[history_commands.size() - 1])) { history_commands.push_back(s); } return s.substr(initial_s_len); default: - DEFAULT_KEY: // unknown buffered key, do nothing if (key_buffer != 0) { key_buffer = 0; @@ -238,8 +235,8 @@ static std::string readline(int fd) clear_str(noncanonical, fd, s); s.insert(cursor_pos, 1, ch); cursor_pos++; - if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) - ; // shut up gcc + if (noncanonical) + (void) write(fd, s.c_str(), s.size() + 1); // send left arrow key to move cursor for (unsigned i = 0; i < s.size() - cursor_pos; i++) { send_key(noncanonical, fd, KEYCODE_LEFT, 3); diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index 61ba5a8..ea64660 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -76,6 +76,8 @@ typedef enum { EXT_INTERNAL_ZFH_MOVE, EXT_SMCSRIND, EXT_SSCSRIND, + EXT_SMCDELEG, + EXT_SSCCFG, EXT_SMCNTRPMF, EXT_ZIMOP, EXT_ZCMOP, diff --git a/riscv/mmu.cc b/riscv/mmu.cc index d950146..616cacc 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -123,7 +123,8 @@ reg_t reg_from_bytes(size_t len, const uint8_t* bytes) bool mmu_t::mmio_ok(reg_t paddr, access_type UNUSED type) { // Disallow access to debug region when not in debug mode - if (paddr >= DEBUG_START && paddr <= DEBUG_END && proc && !proc->state.debug_mode) + static_assert(DEBUG_START == 0); + if (/* paddr >= DEBUG_START && */ paddr <= DEBUG_END && proc && !proc->state.debug_mode) return false; return true; @@ -618,12 +619,14 @@ void mmu_t::register_memtracer(memtracer_t* t) } reg_t mmu_t::get_pmlen(bool effective_virt, reg_t effective_priv, xlate_flags_t flags) const { - if (!proc || proc->get_xlen() != 64 || ((proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(effective_virt)) & MSTATUS_MXR) || flags.hlvx) + if (!proc || proc->get_xlen() != 64 || flags.hlvx) return 0; reg_t pmm = 0; if (effective_priv == PRV_M) pmm = get_field(proc->state.mseccfg->read(), MSECCFG_PMM); + else if ((proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(effective_virt)) & MSTATUS_MXR) + pmm = 0; else if (!effective_virt && (effective_priv == PRV_S || (!proc->extension_enabled('S') && effective_priv == PRV_U))) pmm = get_field(proc->state.menvcfg->read(), MENVCFG_PMM); else if (effective_virt && effective_priv == PRV_S) diff --git a/riscv/mmu.h b/riscv/mmu.h index 3a12355..6695383 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -214,7 +214,10 @@ public: throw trap_load_address_misaligned((proc) ? proc->state.v : false, addr, 0, 0); } - return (float128_t){load<uint64_t>(addr), load<uint64_t>(addr + 8)}; + float128_t res; + res.v[0] = load<uint64_t>(addr); + res.v[1] = load<uint64_t>(addr + 8); + return res; } void cbo_zero(reg_t addr) { @@ -287,8 +290,15 @@ public: template<typename T> T ALWAYS_INLINE fetch_jump_table(reg_t addr) { - auto tlb_entry = translate_insn_addr(addr); - return from_target(*(target_endian<T>*)(tlb_entry.host_offset + addr)); + typedef std::remove_const<std::remove_pointer<decltype(translate_insn_addr_to_host(addr))>::type>::type U; + U parcels[sizeof(T) / sizeof(U)]; + + for (size_t i = 0; i < std::size(parcels); i++) + parcels[i] = *translate_insn_addr_to_host(addr + i * sizeof(U)); + + target_endian<T> res; + memcpy(&res, parcels, sizeof(T)); + return from_target(res); } inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry) diff --git a/riscv/ns16550.cc b/riscv/ns16550.cc index 2805fd8..15e0873 100644 --- a/riscv/ns16550.cc +++ b/riscv/ns16550.cc @@ -328,7 +328,7 @@ void ns16550_t::tick(reg_t UNUSED rtc_ticks) update_interrupt(); } -std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) +std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex @@ -348,7 +348,7 @@ std::string ns16550_generate_dts(const sim_t* sim, const std::vector<std::string return s.str(); } -ns16550_t* ns16550_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& UNUSED sargs) +ns16550_t* ns16550_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& sargs UNUSED) { uint32_t ns16550_shift, ns16550_io_width, ns16550_int_id; if (fdt_parse_ns16550(fdt, base, diff --git a/riscv/plic.cc b/riscv/plic.cc index 14de6df..b6d204b 100644 --- a/riscv/plic.cc +++ b/riscv/plic.cc @@ -343,7 +343,8 @@ bool plic_t::load(reg_t addr, size_t len, uint8_t* bytes) return false; } - if (PRIORITY_BASE <= addr && addr < PENDING_BASE) { + static_assert(PRIORITY_BASE == 0); + if (/* PRIORITY_BASE <= addr && */ addr < PENDING_BASE) { ret = priority_read(addr, &val); } else if (PENDING_BASE <= addr && addr < ENABLE_BASE) { ret = pending_read(addr - PENDING_BASE, &val); @@ -384,7 +385,8 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) write_little_endian_reg(&val, addr, len, bytes); - if (PRIORITY_BASE <= addr && addr < ENABLE_BASE) { + static_assert(PRIORITY_BASE == 0); + if (/* PRIORITY_BASE <= addr && */ addr < ENABLE_BASE) { ret = priority_write(addr, val); } else if (ENABLE_BASE <= addr && addr < CONTEXT_BASE) { uint32_t cntx = (addr - ENABLE_BASE) / ENABLE_PER_HART; @@ -401,7 +403,7 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes) return ret; } -std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& UNUSED sargs) +std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& sargs UNUSED) { std::stringstream s; s << std::hex @@ -424,7 +426,7 @@ std::string plic_generate_dts(const sim_t* sim, const std::vector<std::string>& return s.str(); } -plic_t* plic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& UNUSED sargs) +plic_t* plic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base, const std::vector<std::string>& sargs UNUSED) { uint32_t plic_ndev; if (fdt_parse_plic(fdt, base, &plic_ndev, "riscv,plic0") == 0 || diff --git a/riscv/processor.cc b/riscv/processor.cc index 2917153..cc868e8 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -99,42 +99,6 @@ processor_t::~processor_t() delete disassembler; } -static void bad_option_string(const char *option, const char *value, - const char *msg) -{ - fprintf(stderr, "error: bad %s option '%s'. %s\n", option, value, msg); - abort(); -} - -static std::string get_string_token(std::string str, const char delimiter, size_t& pos) -{ - size_t _pos = pos; - while (pos < str.length() && str[pos] != delimiter) ++pos; - return str.substr(_pos, pos - _pos); -} - -static bool check_pow2(int val) -{ - return ((val & (val - 1))) == 0; -} - -static std::string strtolower(const char* str) -{ - std::string res; - for (const char *r = str; *r; r++) - res += std::tolower(*r); - return res; -} - -static int xlen_to_uxl(int xlen) -{ - if (xlen == 32) - return 1; - if (xlen == 64) - return 2; - abort(); -} - void state_t::reset(processor_t* const proc, reg_t max_isa) { pc = DEFAULT_RSTVEC; @@ -169,7 +133,7 @@ void processor_t::set_debug(bool value) debug = value; for (auto e : custom_extensions) - e.second->set_debug(value); + e.second->set_debug(value, *this); } void processor_t::set_histogram(bool value) @@ -200,7 +164,7 @@ void processor_t::reset() for (auto e : custom_extensions) { // reset any extensions for (auto &csr: e.second->get_csrs(*this)) state.add_csr(csr->address, csr); - e.second->reset(); + e.second->reset(*this); } if (sim) @@ -258,10 +222,10 @@ void processor_t::set_mmu_capability(int cap) break; case IMPL_MMU_SV57: set_impl(IMPL_MMU_SV57, true); - // Fall through + [[fallthrough]]; case IMPL_MMU_SV48: set_impl(IMPL_MMU_SV48, true); - // Fall through + [[fallthrough]]; case IMPL_MMU_SV39: set_impl(IMPL_MMU_SV39, true); set_impl(IMPL_MMU, true); @@ -447,7 +411,10 @@ void processor_t::take_trap(trap_t& t, reg_t epc) // An unexpected trap - a trap when SDT is 1 - traps to M-mode if ((state.prv <= PRV_S && bit < max_xlen) && (((vsdeleg >> bit) & 1) || ((hsdeleg >> bit) & 1))) { - reg_t s = state.sstatus->read(); + // Trap is handled in VS-mode or HS-mode. Read the sstatus of the + // mode that will handle the trap based on the delegation control + reg_t s = (((vsdeleg >> bit) & 1)) ? state.sstatus->read() : + state.nonvirtual_sstatus->read(); supv_double_trap = get_field(s, MSTATUS_SDT); if (supv_double_trap) vsdeleg = hsdeleg = 0; @@ -703,18 +670,17 @@ void processor_t::build_opcode_map() } void processor_t::register_extension(extension_t *x) { - for (auto insn : x->get_instructions()) + for (auto insn : x->get_instructions(*this)) register_custom_insn(insn); build_opcode_map(); - for (auto disasm_insn : x->get_disasms()) + for (auto disasm_insn : x->get_disasms(this)) disassembler->add_insn(disasm_insn); if (!custom_extensions.insert(std::make_pair(x->name(), x)).second) { fprintf(stderr, "extensions must have unique names (got two named \"%s\"!)\n", x->name()); abort(); } - x->set_processor(this); } void processor_t::register_base_instructions() @@ -739,21 +705,27 @@ void processor_t::register_base_instructions() #include "insn_list.h" #undef DEFINE_INSN + #define DEFINE_INSN_UNCOND(name) { \ + insn_desc_t insn = { \ + name##_match, \ + name##_mask, \ + fast_rv32i_##name, \ + fast_rv64i_##name, \ + fast_rv32e_##name, \ + fast_rv64e_##name, \ + logged_rv32i_##name, \ + logged_rv64i_##name, \ + logged_rv32e_##name, \ + logged_rv64e_##name \ + }; \ + register_base_insn(insn); \ + } + // add overlapping instructions first, in order #define DECLARE_OVERLAP_INSN(name, ext) \ name##_overlapping = true; \ if (isa.extension_enabled(ext)) \ - register_base_insn((insn_desc_t) { \ - name##_match, \ - name##_mask, \ - fast_rv32i_##name, \ - fast_rv64i_##name, \ - fast_rv32e_##name, \ - fast_rv64e_##name, \ - logged_rv32i_##name, \ - logged_rv64i_##name, \ - logged_rv32e_##name, \ - logged_rv64e_##name}); + DEFINE_INSN_UNCOND(name); #include "overlap_list.h" #undef DECLARE_OVERLAP_INSN @@ -762,19 +734,10 @@ void processor_t::register_base_instructions() // appear earlier to improve search time on opcode_cache misses. #define DEFINE_INSN(name) \ if (!name##_overlapping) \ - register_base_insn((insn_desc_t) { \ - name##_match, \ - name##_mask, \ - fast_rv32i_##name, \ - fast_rv64i_##name, \ - fast_rv32e_##name, \ - fast_rv64e_##name, \ - logged_rv32i_##name, \ - logged_rv64i_##name, \ - logged_rv32e_##name, \ - logged_rv64e_##name}); + DEFINE_INSN_UNCOND(name); #include "insn_list.h" #undef DEFINE_INSN + #undef DEFINE_INSN_UNCOND // terminate instruction list with a catch-all register_base_insn(insn_desc_t::illegal_instruction); @@ -813,6 +776,11 @@ bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes) return false; } +reg_t processor_t::size() +{ + return PGSIZE; +} + void processor_t::trigger_updated(const std::vector<triggers::trigger_t *> &triggers) { mmu->flush_tlb(); diff --git a/riscv/processor.h b/riscv/processor.h index 4f22cbd..6b611d7 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -109,6 +109,7 @@ struct state_t csr_t_p stvec; virtualized_csr_t_p satp; csr_t_p scause; + csr_t_p scountinhibit; // When taking a trap into HS-mode, we must access the nonvirtualized HS-mode CSRs directly: csr_t_p nonvirtual_stvec; @@ -341,8 +342,9 @@ public: void register_extension(extension_t*); // MMIO slave interface - bool load(reg_t addr, size_t len, uint8_t* bytes); - bool store(reg_t addr, size_t len, const uint8_t* bytes); + bool load(reg_t addr, size_t len, uint8_t* bytes) override; + bool store(reg_t addr, size_t len, const uint8_t* bytes) override; + reg_t size() override; // When true, display disassembly of each instruction that's executed. bool debug; diff --git a/riscv/rocc.cc b/riscv/rocc.cc index 53ee051..9ba4fc1 100644 --- a/riscv/rocc.cc +++ b/riscv/rocc.cc @@ -14,15 +14,15 @@ u.i = insn; \ reg_t xs1 = u.r.xs1 ? RS1 : -1; \ reg_t xs2 = u.r.xs2 ? RS2 : -1; \ - reg_t xd = rocc->custom##n(u.r, xs1, xs2); \ + reg_t xd = rocc->custom##n(p, u.r, xs1, xs2); \ if (u.r.xd) \ WRITE_RD(xd); \ return pc+4; \ } \ \ - reg_t rocc_t::custom##n(rocc_insn_t UNUSED insn, reg_t UNUSED xs1, reg_t UNUSED xs2) \ + reg_t rocc_t::custom##n(processor_t *p, rocc_insn_t UNUSED insn, reg_t UNUSED xs1, reg_t UNUSED xs2) \ { \ - illegal_instruction(); \ + illegal_instruction(*p); \ return 0; \ } @@ -31,25 +31,17 @@ customX(1) customX(2) customX(3) -std::vector<insn_desc_t> rocc_t::get_instructions() +std::vector<insn_desc_t> rocc_t::get_instructions(const processor_t &) { - std::vector<insn_desc_t> insns; - insns.push_back((insn_desc_t){0x0b, 0x7f, - &::illegal_instruction, c0, &::illegal_instruction, c0, - &::illegal_instruction, c0, &::illegal_instruction, c0}); - insns.push_back((insn_desc_t){0x2b, 0x7f, - &::illegal_instruction, c1, &::illegal_instruction, c1, - &::illegal_instruction, c1, &::illegal_instruction, c1}); - insns.push_back((insn_desc_t){0x5b, 0x7f, - &::illegal_instruction, c2, &::illegal_instruction, c2, - &::illegal_instruction, c2, &::illegal_instruction, c2}); - insns.push_back((insn_desc_t){0x7b, 0x7f, - &::illegal_instruction, c3, &::illegal_instruction, c3, - &::illegal_instruction, c0, &::illegal_instruction, c3}); + std::vector<insn_desc_t> insns = { + {0x0b, 0x7f, &::illegal_instruction, c0, &::illegal_instruction, c0, &::illegal_instruction, c0, &::illegal_instruction, c0}, + {0x2b, 0x7f, &::illegal_instruction, c1, &::illegal_instruction, c1, &::illegal_instruction, c1, &::illegal_instruction, c1}, + {0x5b, 0x7f, &::illegal_instruction, c2, &::illegal_instruction, c2, &::illegal_instruction, c2, &::illegal_instruction, c2}, + {0x7b, 0x7f, &::illegal_instruction, c3, &::illegal_instruction, c3, &::illegal_instruction, c0, &::illegal_instruction, c3}}; return insns; } -std::vector<disasm_insn_t*> rocc_t::get_disasms() +std::vector<disasm_insn_t *> rocc_t::get_disasms(const processor_t *) { std::vector<disasm_insn_t*> insns; return insns; diff --git a/riscv/rocc.h b/riscv/rocc.h index d65ec97..d7fee26 100644 --- a/riscv/rocc.h +++ b/riscv/rocc.h @@ -24,12 +24,12 @@ union rocc_insn_union_t class rocc_t : public extension_t { public: - virtual reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom1(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom2(rocc_insn_t insn, reg_t xs1, reg_t xs2); - virtual reg_t custom3(rocc_insn_t insn, reg_t xs1, reg_t xs2); - std::vector<insn_desc_t> get_instructions(); - std::vector<disasm_insn_t*> get_disasms(); + virtual reg_t custom0(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom1(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom2(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + virtual reg_t custom3(processor_t *, rocc_insn_t insn, reg_t xs1, reg_t xs2); + std::vector<insn_desc_t> get_instructions(const processor_t &proc) override; + std::vector<disasm_insn_t *> get_disasms(const processor_t *proc = nullptr) override; }; #define define_custom_func(type_name, ext_name_str, func_name, method_name) \ diff --git a/riscv/sim.cc b/riscv/sim.cc index 81acb1c..fd1c6fb 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -137,7 +137,6 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, dtb = strstream.str(); dts = dtb_to_dts(dtb); } else { - std::pair<reg_t, reg_t> initrd_bounds = cfg->initrd_bounds; std::string device_nodes; for (const device_factory_sargs_t& factory_sargs: device_factories) { const device_factory_t* factory = factory_sargs.first; @@ -238,6 +237,8 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SBARE); } + procs[cpu_idx]->reset(); + cpu_idx++; } @@ -404,10 +405,9 @@ void sim_t::set_rom() char* sim_t::addr_to_mem(reg_t paddr) { if (!paddr_ok(paddr)) return NULL; - auto desc = bus.find_device(paddr); + auto desc = bus.find_device(paddr >> PGSHIFT << PGSHIFT, PGSIZE); if (auto mem = dynamic_cast<abstract_mem_t*>(desc.second)) - if (paddr - desc.first < mem->size()) - return mem->contents(paddr - desc.first); + return mem->contents(paddr - desc.first); return NULL; } diff --git a/riscv/sim.h b/riscv/sim.h index ce5dc6f..da04a88 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -100,8 +100,13 @@ private: remote_bitbang_t* remote_bitbang; std::optional<std::function<void()>> next_interactive_action; - // memory-mapped I/O routines + // If padd corresponds to memory (as opposed to an I/O device), return a + // host pointer corresponding to paddr. + // For these purposes, only memories that include the entire base page + // surrounding paddr are considered; smaller memories are treated as I/O. virtual char* addr_to_mem(reg_t paddr) override; + + // memory-mapped I/O routines virtual bool mmio_load(reg_t paddr, size_t len, uint8_t* bytes) override; virtual bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes) override; void set_rom(); diff --git a/riscv/triggers.cc b/riscv/triggers.cc index e130a87..9c21330 100644 --- a/riscv/triggers.cc +++ b/riscv/triggers.cc @@ -52,7 +52,7 @@ void trigger_t::tdata3_write(processor_t * const proc, const reg_t val) noexcept mhselect = get_field(val, CSR_TEXTRA_MHSELECT(xlen)); sbytemask = get_field(val, CSR_TEXTRA_SBYTEMASK(xlen)); svalue = proc->extension_enabled_const('S') ? get_field(val, CSR_TEXTRA_SVALUE(xlen)) : 0; - sselect = (sselect_t)((proc->extension_enabled_const('S') && get_field(val, CSR_TEXTRA_SSELECT(xlen)) <= SSELECT_MAXVAL) ? get_field(val, CSR_TEXTRA_SSELECT(xlen)) : SSELECT_IGNORE); + sselect = (sselect_t)((proc->extension_enabled_const('S') && get_field(val, CSR_TEXTRA_SSELECT(xlen)) <= SSELECT_MAXVAL) ? get_field(val, CSR_TEXTRA_SSELECT(xlen)) : (reg_t)SSELECT_IGNORE); } static reg_t tcontrol_value(const state_t * state) { @@ -274,7 +274,10 @@ std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(proc 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_NAPOT: + if (maskmax == 0) + return MATCH_EQUAL; + [[fallthrough]]; case MATCH_EQUAL: case MATCH_GE: case MATCH_LT: @@ -675,4 +678,4 @@ reg_t module_t::tinfo_read(unsigned UNUSED index) const noexcept (CSR_TINFO_VERSION_1 << CSR_TINFO_VERSION_OFFSET); } -}; +} diff --git a/riscv/triggers.h b/riscv/triggers.h index 3f1e86f..60ee5ca 100644 --- a/riscv/triggers.h +++ b/riscv/triggers.h @@ -301,6 +301,6 @@ private: std::vector<trigger_t *> triggers; }; -}; +} #endif diff --git a/riscv/v_ext_macros.h b/riscv/v_ext_macros.h index 3e7dc45..5b4d9bd 100644 --- a/riscv/v_ext_macros.h +++ b/riscv/v_ext_macros.h @@ -454,7 +454,7 @@ static inline bool is_overlapped_widen(const int astart, int asize, #define VFP_VF_CMP_PARAMS(width) \ float##width##_t rs1 = f##width(READ_FREG(rs1_num)); \ - float##width##_t vs2 = P.VU.elt<float##width##_t>(rs2_num, i); + float##width##_t UNUSED vs2 = P.VU.elt<float##width##_t>(rs2_num, i); #define VFP_VF_PARAMS(width) \ float##width##_t &vd = P.VU.elt<float##width##_t>(rd_num, i, true); \ @@ -1181,25 +1181,6 @@ VI_VX_ULOOP({ \ #define VI_STRIP(inx) \ reg_t vreg_inx = inx; -#define VI_DUPLICATE_VREG(reg_num, idx_sew) \ -reg_t index[P.VU.vlmax]; \ - for (reg_t i = 0; i < P.VU.vlmax && P.VU.vl->read() != 0; ++i) { \ - switch (idx_sew) { \ - case e8: \ - index[i] = P.VU.elt<uint8_t>(reg_num, i); \ - break; \ - case e16: \ - index[i] = P.VU.elt<uint16_t>(reg_num, i); \ - break; \ - case e32: \ - index[i] = P.VU.elt<uint32_t>(reg_num, i); \ - break; \ - case e64: \ - index[i] = P.VU.elt<uint64_t>(reg_num, i); \ - break; \ - } \ -} - #define VI_LD(stride, offset, elt_width, is_mask_ldst) \ const reg_t nf = insn.v_nf() + 1; \ VI_CHECK_LOAD(elt_width, is_mask_ldst); \ @@ -1218,6 +1199,23 @@ reg_t index[P.VU.vlmax]; \ } \ P.VU.vstart->write(0); +#define VI_LDST_GET_INDEX(elt_width) \ + reg_t index; \ + switch (elt_width) { \ + case e8: \ + index = P.VU.elt<uint8_t>(insn.rs2(), i); \ + break; \ + case e16: \ + index = P.VU.elt<uint16_t>(insn.rs2(), i); \ + break; \ + case e32: \ + index = P.VU.elt<uint32_t>(insn.rs2(), i); \ + break; \ + case e64: \ + index = P.VU.elt<uint64_t>(insn.rs2(), i); \ + break; \ + } \ + #define VI_LD_INDEX(elt_width, is_seg) \ const reg_t nf = insn.v_nf() + 1; \ VI_CHECK_LD_INDEX(elt_width); \ @@ -1226,8 +1224,8 @@ reg_t index[P.VU.vlmax]; \ const reg_t vd = insn.rd(); \ if (!is_seg) \ require(nf == 1); \ - VI_DUPLICATE_VREG(insn.rs2(), elt_width); \ for (reg_t i = 0; i < vl; ++i) { \ + VI_LDST_GET_INDEX(elt_width); \ VI_ELEMENT_SKIP; \ VI_STRIP(i); \ P.VU.vstart->write(i); \ @@ -1235,19 +1233,19 @@ reg_t index[P.VU.vlmax]; \ switch (P.VU.vsew) { \ case e8: \ P.VU.elt<uint8_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint8_t>(baseAddr + index[i] + fn * 1); \ + MMU.load<uint8_t>(baseAddr + index + fn * 1); \ break; \ case e16: \ P.VU.elt<uint16_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint16_t>(baseAddr + index[i] + fn * 2); \ + MMU.load<uint16_t>(baseAddr + index + fn * 2); \ break; \ case e32: \ P.VU.elt<uint32_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint32_t>(baseAddr + index[i] + fn * 4); \ + MMU.load<uint32_t>(baseAddr + index + fn * 4); \ break; \ default: \ P.VU.elt<uint64_t>(vd + fn * flmul, vreg_inx, true) = \ - MMU.load<uint64_t>(baseAddr + index[i] + fn * 8); \ + MMU.load<uint64_t>(baseAddr + index + fn * 8); \ break; \ } \ } \ @@ -1280,27 +1278,27 @@ reg_t index[P.VU.vlmax]; \ const reg_t vs3 = insn.rd(); \ if (!is_seg) \ require(nf == 1); \ - VI_DUPLICATE_VREG(insn.rs2(), elt_width); \ for (reg_t i = 0; i < vl; ++i) { \ + VI_LDST_GET_INDEX(elt_width); \ VI_STRIP(i) \ VI_ELEMENT_SKIP; \ P.VU.vstart->write(i); \ for (reg_t fn = 0; fn < nf; ++fn) { \ switch (P.VU.vsew) { \ case e8: \ - MMU.store<uint8_t>(baseAddr + index[i] + fn * 1, \ + MMU.store<uint8_t>(baseAddr + index + fn * 1, \ P.VU.elt<uint8_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ case e16: \ - MMU.store<uint16_t>(baseAddr + index[i] + fn * 2, \ + MMU.store<uint16_t>(baseAddr + index + fn * 2, \ P.VU.elt<uint16_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ case e32: \ - MMU.store<uint32_t>(baseAddr + index[i] + fn * 4, \ + MMU.store<uint32_t>(baseAddr + index + fn * 4, \ P.VU.elt<uint32_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ default: \ - MMU.store<uint64_t>(baseAddr + index[i] + fn * 8, \ + MMU.store<uint64_t>(baseAddr + index + fn * 8, \ P.VU.elt<uint64_t>(vs3 + fn * flmul, vreg_inx)); \ break; \ } \ diff --git a/softfloat/fall_maxmin.c b/softfloat/fall_maxmin.c index 8d1196e..f1efa87 100644 --- a/softfloat/fall_maxmin.c +++ b/softfloat/fall_maxmin.c @@ -72,13 +72,13 @@ float ## bits ## _t f ## bits ## _min( float ## bits ## _t a, float ## bits ## _ } \ } -COMPARE_MAX(a, b, 16); -COMPARE_MAX(a, b, 32); -COMPARE_MAX(a, b, 64); +COMPARE_MAX(a, b, 16) +COMPARE_MAX(a, b, 32) +COMPARE_MAX(a, b, 64) -COMPARE_MIN(a, b, 16); -COMPARE_MIN(a, b, 32); -COMPARE_MIN(a, b, 64); +COMPARE_MIN(a, b, 16) +COMPARE_MIN(a, b, 32) +COMPARE_MIN(a, b, 64) bfloat16_t bf16_max( bfloat16_t a, bfloat16_t b ) { diff --git a/softfloat/softfloat.mk.in b/softfloat/softfloat.mk.in index 0a38404..899f00a 100644 --- a/softfloat/softfloat.mk.in +++ b/softfloat/softfloat.mk.in @@ -252,3 +252,5 @@ softfloat_test_srcs = softfloat_install_hdrs = \ softfloat.h \ softfloat_types.h \ + +softfloat_CFLAGS = -Wno-sign-compare -Wno-implicit-fallthrough diff --git a/spike_main/spike-log-parser.cc b/spike_main/spike-log-parser.cc index 2c9a543..21166ad 100644 --- a/spike_main/spike-log-parser.cc +++ b/spike_main/spike-log-parser.cc @@ -38,7 +38,6 @@ int main(int UNUSED argc, char** argv) std::regex reg("^core\\s+\\d+:\\s+0x[0-9a-f]+\\s+\\(0x([0-9a-f]+)\\)", std::regex_constants::icase); std::smatch m; - std::ssub_match sm ; while (getline(cin,s)){ if (regex_search(s, m, reg)){ |