aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rwxr-xr-xci-tests/build-spike2
-rw-r--r--ci-tests/custom-csr.cc6
-rw-r--r--ci-tests/test-customext.cc6
-rw-r--r--customext/cflush.cc22
-rw-r--r--customext/dummy_rocc.cc8
-rw-r--r--disasm/disasm.cc20
-rw-r--r--disasm/isa_parser.cc17
-rw-r--r--fdt/fdt.mk.in2
-rw-r--r--fesvr/byteorder.h4
-rw-r--r--fesvr/dtm.cc43
-rw-r--r--fesvr/dtm.h2
-rw-r--r--fesvr/htif.cc13
-rw-r--r--fesvr/memif.cc28
-rw-r--r--fesvr/syscall.cc12
-rw-r--r--riscv/abstract_device.h1
-rw-r--r--riscv/cfg.h2
-rw-r--r--riscv/clint.cc10
-rw-r--r--riscv/csr_init.cc60
-rw-r--r--riscv/csrs.cc126
-rw-r--r--riscv/csrs.h12
-rw-r--r--riscv/debug_module.cc8
-rw-r--r--riscv/debug_module.h5
-rw-r--r--riscv/decode.h6
-rw-r--r--riscv/decode_macros.h8
-rw-r--r--riscv/devices.cc125
-rw-r--r--riscv/devices.h36
-rw-r--r--riscv/dts.cc1
-rw-r--r--riscv/execute.cc15
-rw-r--r--riscv/extension.cc14
-rw-r--r--riscv/extension.h23
-rw-r--r--riscv/interactive.cc27
-rw-r--r--riscv/isa_parser.h2
-rw-r--r--riscv/mmu.cc7
-rw-r--r--riscv/mmu.h16
-rw-r--r--riscv/ns16550.cc4
-rw-r--r--riscv/plic.cc10
-rw-r--r--riscv/processor.cc100
-rw-r--r--riscv/processor.h6
-rw-r--r--riscv/rocc.cc28
-rw-r--r--riscv/rocc.h12
-rw-r--r--riscv/sim.cc8
-rw-r--r--riscv/sim.h7
-rw-r--r--riscv/triggers.cc9
-rw-r--r--riscv/triggers.h2
-rw-r--r--riscv/v_ext_macros.h58
-rw-r--r--softfloat/fall_maxmin.c12
-rw-r--r--softfloat/softfloat.mk.in2
-rw-r--r--spike_main/spike-log-parser.cc1
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)){