From 70663dceb43e4b149fd5b6c2a8cf462f597b867d Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 19 Apr 2023 14:34:36 +0800 Subject: [PATCH 01/72] Ignore vscode project files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6bae0e15f3..73e201a2e1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ autom4te.cache/ .gdb_history .#* *~ +.vscode + From ca2b07c04ec79967696f193064248f72f21b91dd Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 19 Apr 2023 14:35:19 +0800 Subject: [PATCH 02/72] Add fuzz harness --- riscv/sim.h | 2 +- spike_fuzz/Makefile | 62 +++++++++++++++ spike_fuzz/harness.cc | 107 ++++++++++++++++++++++++++ spike_fuzz/spike_fuzz.c | 10 +++ spike_fuzz/utils.cc | 166 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 spike_fuzz/Makefile create mode 100644 spike_fuzz/harness.cc create mode 100644 spike_fuzz/spike_fuzz.c create mode 100644 spike_fuzz/utils.cc diff --git a/riscv/sim.h b/riscv/sim.h index 3109173f19..c9e968c5ef 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -35,6 +35,7 @@ class sim_t : public htif_t, public simif_t FILE *cmd_file); // needed for command line option --cmd ~sim_t(); + void step(size_t n); // step through simulation // run the simulation to completion int run(); void set_debug(bool value); @@ -83,7 +84,6 @@ class sim_t : public htif_t, public simif_t std::ostream sout_; // used for socket and terminal interface processor_t* get_core(const std::string& i); - void step(size_t n); // step through simulation static const size_t INTERLEAVE = 5000; static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core static const size_t CPU_HZ = 1000000000; // 1GHz CPU diff --git a/spike_fuzz/Makefile b/spike_fuzz/Makefile new file mode 100644 index 0000000000..43ac5c2b17 --- /dev/null +++ b/spike_fuzz/Makefile @@ -0,0 +1,62 @@ +LIB_NAME = spike_fuzz +BUILD_DIR = $(abspath ./build) + +CC = clang +CXX = clang++ + +# Spike build +SPIKE_PATH = $(abspath ..) +SPIKE_CONFIGURE = $(SPIKE_PATH)/configure +SPIKE_CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) \ + CXXFLAGS="-O3 -Wno-c99-designator" \ + --with-boost=no --with-boost-asio=no --with-boost-regex=no +SPIKE_MAKEFILE = $(BUILD_DIR)/Makefile + +# spike_fuzz library sources +FUZZ_TARGET = $(BUILD_DIR)/lib$(LIB_NAME).a +FUZZ_SRCS = $(shell find . -maxdepth 1 -name '*.cc') +FUZZ_OBJS = $(addprefix $(BUILD_DIR)/, $(patsubst %.cc, %.o, $(FUZZ_SRCS))) +CXX_FLAGS = -O3 --std=c++20 -fPIC + +ifneq ($(SPIKE_DEBUG),) +CXX_FLAGS += -DLOG_PATH=\"$(BUILD_DIR)/spike.log\" +endif + +SPIKE_INC = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm build +CXX_FLAGS += -I$(SPIKE_PATH) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INC)) + +# spike_fuzz elf dependencies +SPIKE_LIB = libspike_main.a libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a +ELF_LIBS = $(addprefix $(BUILD_DIR)/, $(SPIKE_LIB)) + + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(SPIKE_MAKEFILE): | $(BUILD_DIR) + cd $(BUILD_DIR) && $(SPIKE_CONFIGURE) $(SPIKE_CONFIGURE_FLAGS) + @# Remove -g from Makefile. Don't know why it's always there. + @sed -i 's/ -g / /g' $(SPIKE_MAKEFILE) + +spike: $(SPIKE_MAKEFILE) + $(MAKE) -s -C $(BUILD_DIR) + +$(BUILD_DIR)/%.o: %.cc + $(CXX) $(CXX_FLAGS) $(INC_PATH) $< -c -o $@ + +$(FUZZ_TARGET): $(FUZZ_OBJS) + ar rcs $(FUZZ_TARGET) $(FUZZ_OBJS) + +libfuzz: spike $(FUZZ_TARGET) + +fuzz: spike $(FUZZ_TARGET) spike_fuzz.c + $(CC) -c spike_fuzz.c -o $(BUILD_DIR)/spike_fuzz.o + $(CXX) $(BUILD_DIR)/spike_fuzz.o $(FUZZ_TARGET) $(ELF_LIBS) \ + -o $(BUILD_DIR)/spike_fuzz -ldl -lpthread + +clean: + rm -rf $(BUILD_DIR) + +.DEFAULT_GOAL = $(FUZZ_TARGET) + +.PHONY: clean spike diff --git a/spike_fuzz/harness.cc b/spike_fuzz/harness.cc new file mode 100644 index 0000000000..5fd612c5f1 --- /dev/null +++ b/spike_fuzz/harness.cc @@ -0,0 +1,107 @@ +#include +#include +#include +#include "sim.h" +#include "mmu.h" + + +#define CONFIG_MSIZE (1024 * 1024 * 1024UL) + +std::vector parse_mem_layout(const char *arg); +std::vector> make_mems(const std::vector &layout); + +static sim_t *spike_init(const uint8_t *data, size_t size) { + std::vector difftest_htif_args; + difftest_htif_args.push_back(""); + char mem_layout_str[100]; + sprintf(mem_layout_str, "0x%x:0x%lx", DRAM_BASE, CONFIG_MSIZE); + auto memory_layout = parse_mem_layout(mem_layout_str); + std::vector> difftest_plugin_devices{}; + auto const cfg = new cfg_t( + // std::pair default_initrd_bounds, + std::make_pair(0, 0), + // const char *default_bootargs, + nullptr, + // const char *default_isa, + "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval", + // const char *default_priv + DEFAULT_PRIV, + // const char *default_varch, + DEFAULT_VARCH, + // const bool default_misaligned, + false, + // const endianness_t default_endianness, + endianness_little, + // const reg_t default_pmpregions, + 0, + // const std::vector &default_mem_layout, + memory_layout, + // const std::vector default_hartids, + std::vector{0}, + // bool default_real_time_clint, + false, + // const reg_t default_trigger_count + 0 + ); + + const debug_module_config_t difftest_dm_config = { + .progbufsize = 2, + .max_sba_data_width = 0, + .require_authentication = false, + .abstract_rti = 0, + .support_hasel = true, + .support_abstract_csr_access = true, + .support_abstract_fpr_access = true, + .support_haltgroups = false, + .support_impebreak = false + }; + sim_t *s = new sim_t( + // const cfg_t *cfg, + cfg, + // bool halted, + false, + // std::vector> mems + make_mems(memory_layout), + // std::vector> plugin_devices + difftest_plugin_devices, + // const std::vector& args + difftest_htif_args, + // const debug_module_config_t &dm_config + difftest_dm_config, + // const char *log_path +#ifndef LOG_PATH + nullptr, +#else + LOG_PATH, +#endif // LOG_PATH + //bool dtb_enabled, const char *dtb_file, bool socket_enabled, FILE *cmd_file + false, nullptr, false, nullptr + ); + + // enable commit log +#ifdef LOG_PATH + printf("commit log is enabled\n"); + s->configure_log(false, true); +#endif // LOG_PATH + + // set initialized states + auto p = s->get_core(0UL); + // set pc to 0x8000_0000 + p->get_state()->pc = 0x80000000; + // initialize the memory with specified data + auto mmu = p->get_mmu(); + for (size_t i = 0; i < size; i++) { + mmu->store(DRAM_BASE + i, data[i]); + } + + return s; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + auto s = spike_init(data, size); + for (int i = 0; i < 1000; i++) { + s->step(1); + } + delete s; + return 0; +} diff --git a/spike_fuzz/spike_fuzz.c b/spike_fuzz/spike_fuzz.c new file mode 100644 index 0000000000..2d29deee75 --- /dev/null +++ b/spike_fuzz/spike_fuzz.c @@ -0,0 +1,10 @@ +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int main() { + const uint8_t data[32] = { + 0x13, 0x04, 0x00, 0x00, 0x17, 0xa1, 0x00, 0x00, 0x13, 0x01, 0xc1, 0xff, 0xef, 0x00, 0x80, 0x0a}; + LLVMFuzzerTestOneInput(data, 32); +} diff --git a/spike_fuzz/utils.cc b/spike_fuzz/utils.cc new file mode 100644 index 0000000000..c2be837da0 --- /dev/null +++ b/spike_fuzz/utils.cc @@ -0,0 +1,166 @@ +// #include +// #include +// #include +#include "arith.h" +#include "sim.h" +#include "mmu.h" +#include "disasm.h" + + +bool sort_mem_region(const mem_cfg_t &a, const mem_cfg_t &b) +{ + if (a.get_base() == b.get_base()) + return (a.get_size() < b.get_size()); + else + return (a.get_base() < b.get_base()); +} + +static bool check_mem_overlap(const mem_cfg_t& L, const mem_cfg_t& R) +{ + return std::max(L.get_base(), R.get_base()) <= std::min(L.get_inclusive_end(), R.get_inclusive_end()); +} + +static bool check_if_merge_covers_64bit_space(const mem_cfg_t& L, + const mem_cfg_t& R) +{ + if (!check_mem_overlap(L, R)) + return false; + + auto start = std::min(L.get_base(), R.get_base()); + auto end = std::max(L.get_inclusive_end(), R.get_inclusive_end()); + + return (start == 0ull) && (end == std::numeric_limits::max()); +} + +static mem_cfg_t merge_mem_regions(const mem_cfg_t& L, const mem_cfg_t& R) +{ + // one can merge only intersecting regions + assert(check_mem_overlap(L, R)); + + const auto merged_base = std::min(L.get_base(), R.get_base()); + const auto merged_end_incl = std::max(L.get_inclusive_end(), R.get_inclusive_end()); + const auto merged_size = merged_end_incl - merged_base + 1; + + return mem_cfg_t(merged_base, merged_size); +} + + +// check the user specified memory regions and merge the overlapping or +// eliminate the containing parts +static std::vector +merge_overlapping_memory_regions(std::vector mems) +{ + if (mems.empty()) + return {}; + + std::sort(mems.begin(), mems.end(), sort_mem_region); + + std::vector merged_mem; + merged_mem.push_back(mems.front()); + + for (auto mem_it = std::next(mems.begin()); mem_it != mems.end(); ++mem_it) { + const auto& mem_int = *mem_it; + if (!check_mem_overlap(merged_mem.back(), mem_int)) { + merged_mem.push_back(mem_int); + continue; + } + // there is a weird corner case preventing two memory regions from being + // merged: if the resulting size of a region is 2^64 bytes - currently, + // such regions are not representable by mem_cfg_t class (because the + // actual size field is effectively a 64 bit value) + // so we create two smaller memory regions that total for 2^64 bytes as + // a workaround + if (check_if_merge_covers_64bit_space(merged_mem.back(), mem_int)) { + merged_mem.clear(); + merged_mem.push_back(mem_cfg_t(0ull, 0ull - PGSIZE)); + merged_mem.push_back(mem_cfg_t(0ull - PGSIZE, PGSIZE)); + break; + } + merged_mem.back() = merge_mem_regions(merged_mem.back(), mem_int); + } + + return merged_mem; +} + + +std::vector parse_mem_layout(const char* arg) +{ + std::vector res; + + // handle legacy mem argument + char* p; + auto mb = strtoull(arg, &p, 0); + if (*p == 0) { + reg_t size = reg_t(mb) << 20; + if (size != (size_t)size) + throw std::runtime_error("Size would overflow size_t"); + res.push_back(mem_cfg_t(reg_t(DRAM_BASE), size)); + return res; + } + + // handle base/size tuples + while (true) { + auto base = strtoull(arg, &p, 0); + // if (!*p || *p != ':') + // help(); + auto size = strtoull(p + 1, &p, 0); + + // page-align base and size + auto base0 = base, size0 = size; + size += base0 % PGSIZE; + base -= base0 % PGSIZE; + if (size % PGSIZE != 0) + size += PGSIZE - size % PGSIZE; + + if (size != size0) { + fprintf(stderr, "Warning: the memory at [0x%llX, 0x%llX] has been realigned\n" + "to the %ld KiB page size: [0x%llX, 0x%llX]\n", + base0, base0 + size0 - 1, long(PGSIZE / 1024), base, base + size - 1); + } + + if (!mem_cfg_t::check_if_supported(base, size)) { + fprintf(stderr, "Unsupported memory region " + "{base = 0x%llX, size = 0x%llX} specified\n", + base, size); + exit(EXIT_FAILURE); + } + + const unsigned long long max_allowed_pa = (1ull << MAX_PADDR_BITS) - 1ull; + assert(max_allowed_pa <= std::numeric_limits::max()); + mem_cfg_t mem_region(base, size); + if (mem_region.get_inclusive_end() > max_allowed_pa) { + int bits_required = 64 - clz(mem_region.get_inclusive_end()); + fprintf(stderr, "Unsupported memory region " + "{base = 0x%" PRIX64 ", size = 0x%" PRIX64 "} specified," + " which requires %d bits of physical address\n" + " The largest accessible physical address " + "is 0x%llX (defined by MAX_PADDR_BITS constant, which is %d)\n", + mem_region.get_base(), mem_region.get_size(), bits_required, + max_allowed_pa, MAX_PADDR_BITS); + exit(EXIT_FAILURE); + } + + res.push_back(mem_region); + + if (!*p) + break; + // if (*p != ',') + // help(); + arg = p + 1; + } + + auto merged_mem = merge_overlapping_memory_regions(res); + + assert(!merged_mem.empty()); + return merged_mem; +} + +std::vector> make_mems(const std::vector &layout) +{ + std::vector> mems; + mems.reserve(layout.size()); + for (const auto &cfg : layout) { + mems.push_back(std::make_pair(cfg.get_base(), new mem_t(cfg.get_size()))); + } + return mems; +} From 9f2036b3b690b8e496e8fdffb83e1412320287ae Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 19 Apr 2023 17:19:50 +0800 Subject: [PATCH 03/72] Add test interface to main --- spike_fuzz/harness.cc | 2 +- spike_fuzz/spike_fuzz.c | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/spike_fuzz/harness.cc b/spike_fuzz/harness.cc index 5fd612c5f1..bb3ded5cfa 100644 --- a/spike_fuzz/harness.cc +++ b/spike_fuzz/harness.cc @@ -5,7 +5,7 @@ #include "mmu.h" -#define CONFIG_MSIZE (1024 * 1024 * 1024UL) +extern "C" const size_t CONFIG_MSIZE = 2 * 1024 * 1024 * 1024UL; std::vector parse_mem_layout(const char *arg); std::vector> make_mems(const std::vector &layout); diff --git a/spike_fuzz/spike_fuzz.c b/spike_fuzz/spike_fuzz.c index 2d29deee75..7710650ea2 100644 --- a/spike_fuzz/spike_fuzz.c +++ b/spike_fuzz/spike_fuzz.c @@ -1,10 +1,39 @@ #include #include +#include +#include +extern size_t CONFIG_MSIZE; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); -int main() { - const uint8_t data[32] = { - 0x13, 0x04, 0x00, 0x00, 0x17, 0xa1, 0x00, 0x00, 0x13, 0x01, 0xc1, 0xff, 0xef, 0x00, 0x80, 0x0a}; - LLVMFuzzerTestOneInput(data, 32); +size_t load_from_file(char *filename, uint8_t *data) { + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + printf("Can not open '%s'\n", filename); + return 0; + } + + fseek(fp, 0, SEEK_END); + size_t img_size = ftell(fp); + if (img_size > CONFIG_MSIZE) { + img_size = CONFIG_MSIZE; + } + + fseek(fp, 0, SEEK_SET); + fread(data, img_size, 1, fp); + + fclose(fp); + + return img_size; +} + +int main(int argc, char *argv[]) { + uint8_t *data = malloc(CONFIG_MSIZE); + for (int i = 1; i < argc; i++) { + printf("Running %s\n", argv[i]); + size_t size = load_from_file(argv[i], data); + LLVMFuzzerTestOneInput(data, size); + } + free(data); + return 0; } From 58e929945ec8944795cc544b317e53b473ce18fb Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Apr 2023 13:15:34 +0800 Subject: [PATCH 04/72] Update Makefile to support libafl --- spike_fuzz/Makefile | 63 ++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/spike_fuzz/Makefile b/spike_fuzz/Makefile index 43ac5c2b17..4a51853113 100644 --- a/spike_fuzz/Makefile +++ b/spike_fuzz/Makefile @@ -1,33 +1,48 @@ -LIB_NAME = spike_fuzz BUILD_DIR = $(abspath ./build) CC = clang CXX = clang++ -# Spike build -SPIKE_PATH = $(abspath ..) +# build spike +SPIKE_PATH = $(abspath ..) SPIKE_CONFIGURE = $(SPIKE_PATH)/configure -SPIKE_CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) \ - CXXFLAGS="-O3 -Wno-c99-designator" \ + +SPIKE_CFLAGS = -O3 -g0 +SPIKE_CXXFLAGS = -O3 -Wno-c99-designator -g0 +SPIKE_LDFLAGS = +ifneq ($(filter fuzz, $(MAKECMDGOALS)),) +SPIKE_CFLAGS += -fsanitize-coverage=trace-pc-guard +SPIKE_CXXFLAGS += -fsanitize-coverage=trace-pc-guard +SPIKE_LDFLAGS += -fsanitize-coverage=trace-pc-guard +endif + +SPIKE_CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) CFLAGS="$(SPIKE_CFLAGS)" \ + CXXFLAGS="$(SPIKE_CXXFLAGS)" LDFLAGS="$(SPIKE_LDFLAGS)" \ --with-boost=no --with-boost-asio=no --with-boost-regex=no SPIKE_MAKEFILE = $(BUILD_DIR)/Makefile -# spike_fuzz library sources -FUZZ_TARGET = $(BUILD_DIR)/lib$(LIB_NAME).a -FUZZ_SRCS = $(shell find . -maxdepth 1 -name '*.cc') -FUZZ_OBJS = $(addprefix $(BUILD_DIR)/, $(patsubst %.cc, %.o, $(FUZZ_SRCS))) -CXX_FLAGS = -O3 --std=c++20 -fPIC +# spike_fuzz sources +FUZZ_SRCS = $(shell find . -maxdepth 1 -name '*.cc') +FUZZ_OBJS = $(addprefix $(BUILD_DIR)/, $(patsubst %.cc, %.o, $(FUZZ_SRCS))) +CXX_FLAGS = -O3 --std=c++20 -fPIC + +ifneq ($(filter fuzz, $(MAKECMDGOALS)),) +CXX_FLAGS += -fsanitize-coverage=trace-pc-guard +endif ifneq ($(SPIKE_DEBUG),) CXX_FLAGS += -DLOG_PATH=\"$(BUILD_DIR)/spike.log\" endif -SPIKE_INC = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm build -CXX_FLAGS += -I$(SPIKE_PATH) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INC)) +SPIKE_INC = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm build +CXX_FLAGS += -I$(SPIKE_PATH) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INC)) # spike_fuzz elf dependencies -SPIKE_LIB = libspike_main.a libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a -ELF_LIBS = $(addprefix $(BUILD_DIR)/, $(SPIKE_LIB)) +CATISS_PATH = $(abspath $(SPIKE_PATH)/..) +CATISS_LINK = $(CATISS_PATH)/../target/release/libcatiss.a + +SPIKE_LIB = libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a +SPIKE_LINK = $(addprefix $(BUILD_DIR)/, $(SPIKE_LIB)) $(BUILD_DIR): @@ -35,8 +50,6 @@ $(BUILD_DIR): $(SPIKE_MAKEFILE): | $(BUILD_DIR) cd $(BUILD_DIR) && $(SPIKE_CONFIGURE) $(SPIKE_CONFIGURE_FLAGS) - @# Remove -g from Makefile. Don't know why it's always there. - @sed -i 's/ -g / /g' $(SPIKE_MAKEFILE) spike: $(SPIKE_MAKEFILE) $(MAKE) -s -C $(BUILD_DIR) @@ -44,19 +57,23 @@ spike: $(SPIKE_MAKEFILE) $(BUILD_DIR)/%.o: %.cc $(CXX) $(CXX_FLAGS) $(INC_PATH) $< -c -o $@ -$(FUZZ_TARGET): $(FUZZ_OBJS) - ar rcs $(FUZZ_TARGET) $(FUZZ_OBJS) +libfuzz: spike $(FUZZ_OBJS) + +libcatiss: + cd $(CATISS_PATH) && cargo build --release -q -libfuzz: spike $(FUZZ_TARGET) +fuzz: libfuzz libcatiss + $(CXX) $(FUZZ_OBJS) $(CATISS_LINK) $(SPIKE_LINK) \ + -o $(BUILD_DIR)/spike_fuzz -ldl -lpthread -lrt -fuzz: spike $(FUZZ_TARGET) spike_fuzz.c +dummy: libfuzz spike_fuzz.c $(CC) -c spike_fuzz.c -o $(BUILD_DIR)/spike_fuzz.o - $(CXX) $(BUILD_DIR)/spike_fuzz.o $(FUZZ_TARGET) $(ELF_LIBS) \ + $(CXX) $(BUILD_DIR)/spike_fuzz.o $(FUZZ_OBJS) $(SPIKE_LINK) \ -o $(BUILD_DIR)/spike_fuzz -ldl -lpthread clean: rm -rf $(BUILD_DIR) -.DEFAULT_GOAL = $(FUZZ_TARGET) +.DEFAULT_GOAL = dummy -.PHONY: clean spike +.PHONY: clean spike fuzz dummy libfuzz libcatiss From 2f570c6adc00dd8fc6ce27021aba208449cc72df Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Apr 2023 13:55:18 +0800 Subject: [PATCH 05/72] Makefile: fix dependency on spike generated files --- spike_fuzz/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spike_fuzz/Makefile b/spike_fuzz/Makefile index 4a51853113..d11b63d51c 100644 --- a/spike_fuzz/Makefile +++ b/spike_fuzz/Makefile @@ -34,8 +34,9 @@ ifneq ($(SPIKE_DEBUG),) CXX_FLAGS += -DLOG_PATH=\"$(BUILD_DIR)/spike.log\" endif -SPIKE_INC = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm build +SPIKE_INC = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm CXX_FLAGS += -I$(SPIKE_PATH) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INC)) +CXX_FLAGS += -I$(BUILD_DIR) # spike_fuzz elf dependencies CATISS_PATH = $(abspath $(SPIKE_PATH)/..) @@ -54,7 +55,7 @@ $(SPIKE_MAKEFILE): | $(BUILD_DIR) spike: $(SPIKE_MAKEFILE) $(MAKE) -s -C $(BUILD_DIR) -$(BUILD_DIR)/%.o: %.cc +$(BUILD_DIR)/%.o: %.cc spike $(CXX) $(CXX_FLAGS) $(INC_PATH) $< -c -o $@ libfuzz: spike $(FUZZ_OBJS) From ceab3574633e112377adde34cfcb7b5a9574d402 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Apr 2023 16:46:15 +0800 Subject: [PATCH 06/72] Disable default signal handlers. --- fesvr/htif.cc | 6 +++--- riscv/sim.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 3f93f7b507..80be40a017 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -49,9 +49,9 @@ htif_t::htif_t() tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false), syscall_proxy(this) { - signal(SIGINT, &handle_signal); - signal(SIGTERM, &handle_signal); - signal(SIGABRT, &handle_signal); // we still want to call static destructors + // signal(SIGINT, &handle_signal); + // signal(SIGTERM, &handle_signal); + // signal(SIGABRT, &handle_signal); // we still want to call static destructors } htif_t::htif_t(int argc, char** argv) : htif_t() diff --git a/riscv/sim.cc b/riscv/sim.cc index dcbd469d32..500542837b 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -59,7 +59,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, remote_bitbang(NULL), debug_module(this, dm_config) { - signal(SIGINT, &handle_signal); + // signal(SIGINT, &handle_signal); sout_.rdbuf(std::cerr.rdbuf()); // debug output goes to stderr by default From a15ba9305504696b34595ea09123bb90dc0af7cb Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Apr 2023 16:47:04 +0800 Subject: [PATCH 07/72] Close file descriptors in destructor of syscall_t --- fesvr/syscall.cc | 13 ++++++++++--- fesvr/syscall.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index 875ffb7321..e277be19bf 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -174,9 +174,16 @@ syscall_t::syscall_t(htif_t* htif) if (stdin_fd < 0 || stdout_fd0 < 0 || stdout_fd1 < 0) throw std::runtime_error("could not dup stdin/stdout"); - fds.alloc(stdin_fd); // stdin -> stdin - fds.alloc(stdout_fd0); // stdout -> stdout - fds.alloc(stdout_fd1); // stderr -> stdout + fds_index.push_back(fds.alloc(stdin_fd)); // stdin -> stdin + fds_index.push_back(fds.alloc(stdout_fd0)); // stdout -> stdout + fds_index.push_back(fds.alloc(stdout_fd1)); // stderr -> stdout +} + +syscall_t::~syscall_t() { + for (auto i: fds_index) { + close(fds.lookup(i)); + fds.dealloc(i); + } } std::string syscall_t::do_chroot(const char* fn) diff --git a/fesvr/syscall.h b/fesvr/syscall.h index 4915efd689..c002e6c66e 100644 --- a/fesvr/syscall.h +++ b/fesvr/syscall.h @@ -28,6 +28,7 @@ class syscall_t : public device_t { public: syscall_t(htif_t*); + ~syscall_t(); void set_chroot(const char* where); @@ -38,6 +39,7 @@ class syscall_t : public device_t memif_t* memif; std::vector table; fds_t fds; + std::vector fds_index; void handle_syscall(command_t cmd); void dispatch(addr_t mm); From bf483df5eb0f5551e440277e5fd81e1820b1c9e4 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 21 Apr 2023 14:59:28 +0800 Subject: [PATCH 08/72] fuzz: remove catiss dependencies Moved to catiss repo. --- spike_fuzz/Makefile | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/spike_fuzz/Makefile b/spike_fuzz/Makefile index d11b63d51c..5d45e3c214 100644 --- a/spike_fuzz/Makefile +++ b/spike_fuzz/Makefile @@ -1,8 +1,11 @@ BUILD_DIR = $(abspath ./build) -CC = clang +CC = clang CXX = clang++ +AFL_CC ?= $(CC) +AFL_CXX ?= $(CXX) + # build spike SPIKE_PATH = $(abspath ..) SPIKE_CONFIGURE = $(SPIKE_PATH)/configure @@ -10,11 +13,6 @@ SPIKE_CONFIGURE = $(SPIKE_PATH)/configure SPIKE_CFLAGS = -O3 -g0 SPIKE_CXXFLAGS = -O3 -Wno-c99-designator -g0 SPIKE_LDFLAGS = -ifneq ($(filter fuzz, $(MAKECMDGOALS)),) -SPIKE_CFLAGS += -fsanitize-coverage=trace-pc-guard -SPIKE_CXXFLAGS += -fsanitize-coverage=trace-pc-guard -SPIKE_LDFLAGS += -fsanitize-coverage=trace-pc-guard -endif SPIKE_CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) CFLAGS="$(SPIKE_CFLAGS)" \ CXXFLAGS="$(SPIKE_CXXFLAGS)" LDFLAGS="$(SPIKE_LDFLAGS)" \ @@ -26,10 +24,6 @@ FUZZ_SRCS = $(shell find . -maxdepth 1 -name '*.cc') FUZZ_OBJS = $(addprefix $(BUILD_DIR)/, $(patsubst %.cc, %.o, $(FUZZ_SRCS))) CXX_FLAGS = -O3 --std=c++20 -fPIC -ifneq ($(filter fuzz, $(MAKECMDGOALS)),) -CXX_FLAGS += -fsanitize-coverage=trace-pc-guard -endif - ifneq ($(SPIKE_DEBUG),) CXX_FLAGS += -DLOG_PATH=\"$(BUILD_DIR)/spike.log\" endif @@ -39,9 +33,6 @@ CXX_FLAGS += -I$(SPIKE_PATH) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INC)) CXX_FLAGS += -I$(BUILD_DIR) # spike_fuzz elf dependencies -CATISS_PATH = $(abspath $(SPIKE_PATH)/..) -CATISS_LINK = $(CATISS_PATH)/../target/release/libcatiss.a - SPIKE_LIB = libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a SPIKE_LINK = $(addprefix $(BUILD_DIR)/, $(SPIKE_LIB)) @@ -53,19 +44,15 @@ $(SPIKE_MAKEFILE): | $(BUILD_DIR) cd $(BUILD_DIR) && $(SPIKE_CONFIGURE) $(SPIKE_CONFIGURE_FLAGS) spike: $(SPIKE_MAKEFILE) - $(MAKE) -s -C $(BUILD_DIR) + $(MAKE) -s -C $(BUILD_DIR) CC=$(AFL_CC) CXX=$(AFL_CXX) $(BUILD_DIR)/%.o: %.cc spike - $(CXX) $(CXX_FLAGS) $(INC_PATH) $< -c -o $@ + $(AFL_CXX) $(CXX_FLAGS) $(INC_PATH) $< -c -o $@ libfuzz: spike $(FUZZ_OBJS) -libcatiss: - cd $(CATISS_PATH) && cargo build --release -q - -fuzz: libfuzz libcatiss - $(CXX) $(FUZZ_OBJS) $(CATISS_LINK) $(SPIKE_LINK) \ - -o $(BUILD_DIR)/spike_fuzz -ldl -lpthread -lrt +fuzz: libfuzz + $(AFL_CXX) $(FUZZ_OBJS) $(SPIKE_LINK) -o $(BUILD_DIR)/spike_fuzz dummy: libfuzz spike_fuzz.c $(CC) -c spike_fuzz.c -o $(BUILD_DIR)/spike_fuzz.o @@ -77,4 +64,4 @@ clean: .DEFAULT_GOAL = dummy -.PHONY: clean spike fuzz dummy libfuzz libcatiss +.PHONY: clean spike fuzz dummy libfuzz From 771350721d5d40bf461c9a8beadd099855b4807c Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 20 Jun 2023 10:29:46 +0800 Subject: [PATCH 09/72] fuzz: use macros to switch code blocks --- fesvr/htif.cc | 10 ++++++---- riscv/sim.h | 5 +++++ spike_fuzz/Makefile | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 80be40a017..4643544cd3 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -49,9 +49,11 @@ htif_t::htif_t() tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false), syscall_proxy(this) { - // signal(SIGINT, &handle_signal); - // signal(SIGTERM, &handle_signal); - // signal(SIGABRT, &handle_signal); // we still want to call static destructors +#ifdef SPIKE_FUZZ + signal(SIGINT, &handle_signal); + signal(SIGTERM, &handle_signal); + signal(SIGABRT, &handle_signal); // we still want to call static destructors +#endif // SPIKE_FUZZ } htif_t::htif_t(int argc, char** argv) : htif_t() @@ -116,7 +118,7 @@ std::map htif_t::load_payload(const std::string& payload, else throw std::runtime_error( "could not open " + payload + "; searched paths:\n" + - "\t. (current directory)\n" + + "\t. (current directory)\n" + "\t" + PREFIX TARGET_DIR + " (based on configured --prefix and --with-target)" ); } diff --git a/riscv/sim.h b/riscv/sim.h index c9e968c5ef..bc3ef9eb95 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -35,7 +35,9 @@ class sim_t : public htif_t, public simif_t FILE *cmd_file); // needed for command line option --cmd ~sim_t(); +#ifdef SPIKE_FUZZ void step(size_t n); // step through simulation +#endif // SPIKE_FUZZ // run the simulation to completion int run(); void set_debug(bool value); @@ -84,6 +86,9 @@ class sim_t : public htif_t, public simif_t std::ostream sout_; // used for socket and terminal interface processor_t* get_core(const std::string& i); +#ifndef SPIKE_FUZZ + void step(size_t n); // step through simulation +#endif // SPIKE_FUZZ static const size_t INTERLEAVE = 5000; static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core static const size_t CPU_HZ = 1000000000; // 1GHz CPU diff --git a/spike_fuzz/Makefile b/spike_fuzz/Makefile index 5d45e3c214..05dbff8380 100644 --- a/spike_fuzz/Makefile +++ b/spike_fuzz/Makefile @@ -10,8 +10,8 @@ AFL_CXX ?= $(CXX) SPIKE_PATH = $(abspath ..) SPIKE_CONFIGURE = $(SPIKE_PATH)/configure -SPIKE_CFLAGS = -O3 -g0 -SPIKE_CXXFLAGS = -O3 -Wno-c99-designator -g0 +SPIKE_CFLAGS = -O3 -g0 -DSPIKE_FUZZ +SPIKE_CXXFLAGS = -O3 -Wno-c99-designator -g0 -DSPIKE_FUZZ SPIKE_LDFLAGS = SPIKE_CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) CFLAGS="$(SPIKE_CFLAGS)" \ @@ -22,7 +22,7 @@ SPIKE_MAKEFILE = $(BUILD_DIR)/Makefile # spike_fuzz sources FUZZ_SRCS = $(shell find . -maxdepth 1 -name '*.cc') FUZZ_OBJS = $(addprefix $(BUILD_DIR)/, $(patsubst %.cc, %.o, $(FUZZ_SRCS))) -CXX_FLAGS = -O3 --std=c++20 -fPIC +CXX_FLAGS = -O3 --std=c++20 -fPIC -DSPIKE_FUZZ ifneq ($(SPIKE_DEBUG),) CXX_FLAGS += -DLOG_PATH=\"$(BUILD_DIR)/spike.log\" From b95048ea6f0eef2cf629c12deb51fc12e20027d0 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 20 Jun 2023 19:20:43 +0800 Subject: [PATCH 10/72] Rewrite difftest support for Spike as a REF Migrate the original code from OpenXiangShan and re-write it with C++ style classes for the upstream riscv-isa-sim. --- difftest/.gitignore | 1 + difftest/Makefile | 75 +++++++++ difftest/difftest.cc | 332 ++++++++++++++++++++++++++++++++++++++++ difftest/difftest.h | 111 ++++++++++++++ difftest/dummy_debug.cc | 35 +++++ difftest/dummy_debug.h | 23 +++ fesvr/htif.cc | 15 +- riscv/sim.cc | 6 +- riscv/sim.h | 17 +- 9 files changed, 605 insertions(+), 10 deletions(-) create mode 100644 difftest/.gitignore create mode 100644 difftest/Makefile create mode 100644 difftest/difftest.cc create mode 100644 difftest/difftest.h create mode 100644 difftest/dummy_debug.cc create mode 100644 difftest/dummy_debug.h diff --git a/difftest/.gitignore b/difftest/.gitignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/difftest/.gitignore @@ -0,0 +1 @@ +build diff --git a/difftest/Makefile b/difftest/Makefile new file mode 100644 index 0000000000..ba47243af6 --- /dev/null +++ b/difftest/Makefile @@ -0,0 +1,75 @@ +CC = clang +CXX = clang++ + +GUEST_ISA = riscv64 +BUILD_DIR = $(abspath ./build) +TARGET = $(BUILD_DIR)/$(GUEST_ISA)-spike-so + +# Dependencies for building Spike +SPIKE_PATH = $(abspath ..) +SPIKE_TARGET = $(BUILD_DIR)/spike +SPIKE_MAKEFILE = $(BUILD_DIR)/Makefile + +SPIKE_CFLAGS = -O3 -DDIFFTEST +SPIKE_CXXFLAGS = -O3 -DDIFFTEST -Wno-c99-designator +SPIKE_LDFLAGS = + +ifneq ($(CPU),) +SPIKE_CFLAGS += -DCPU_$(CPU) +SPIKE_CXXFLAGS += -DCPU_$(CPU) +endif + +ifeq ($(DEBUG),) +SPIKE_CFLAGS += -g0 +SPIKE_CXXFLAGS += -g0 +endif + +CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) \ + --with-boost=no --with-boost-asio=no --with-boost-regex=no \ + CFLAGS="$(SPIKE_CFLAGS)" CXXFLAGS="$(SPIKE_CXXFLAGS)" \ + LDFLAGS="$(SPIKE_LDFLAGS)" + +SPIKE_INCS = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm +INC_PATH = -I$(SPIKE_PATH) -I$(BUILD_DIR) $(addprefix -I$(SPIKE_PATH)/, $(SPIKE_INCS)) + +SPIKE_SRCS = $(shell find $(SPIKE_PATH) -maxdepth 2 -name '*.cc') \ + $(shell find $(SPIKE_PATH) -maxdepth 2 -name '*.h') +SPIKE_LIBS = libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a +INC_LIBS = $(addprefix $(BUILD_DIR)/, $(SPIKE_LIBS)) + +# We need some utilities from spike +CXX_UTILS = $(BUILD_DIR)/difftest_utils.cc + +$(CXX_UTILS): $(SPIKE_PATH)/spike_main/spike.cc + cp $< $(CXX_UTILS) + @sed -i 's/static //g' $@ + @sed -i 's/int main/static int spike_main/g' $@ + +# Dependencies for building the difftest dynamic library +DIFFTEST_SOURCES = $(shell find . -maxdepth 1 -name '*.cc') $(CXX_UTILS) +DIFFTEST_HEADERS = $(shell find . -maxdepth 1 -name '*.h') +CXXFLAGS = $(SPIKE_CXXFLAGS) --std=c++17 -shared -fPIC -flto + +ifneq ($(DEBUG),) +CONFIGURE_FLAGS += --enable-commitlog +CXXFLAGS += -DDIFFTEST_LOG_FILE=\"$(NOOP_HOME)/build/spike.log\" +endif + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(SPIKE_MAKEFILE): $(SPIKE_PATH)/configure | $(BUILD_DIR) + cd $(@D) && $(abspath $(SPIKE_PATH))/configure $(CONFIGURE_FLAGS) + +$(SPIKE_TARGET): $(SPIKE_MAKEFILE) $(SPIKE_SRCS) + $(MAKE) -s -C $(BUILD_DIR) + +$(TARGET): $(SPIKE_TARGET) $(DIFFTEST_SOURCES) $(DIFFTEST_HEADERS) | $(BUILD_DIR) + $(CXX) $(CXXFLAGS) $(INC_PATH) $(DIFFTEST_SOURCES) $(INC_LIBS) -o $@ + +clean: + rm -rf $(BUILD_DIR) + +.DEFAULT_GOAL = $(TARGET) + +.PHONY: clean diff --git a/difftest/difftest.cc b/difftest/difftest.cc new file mode 100644 index 0000000000..d6b6d552b7 --- /dev/null +++ b/difftest/difftest.cc @@ -0,0 +1,332 @@ +#include "decode_macros.h" +#include "difftest.h" +#include "disasm.h" +#include "softfloat.h" + +// Some static utilities and configurations +static debug_module_config_t difftest_dm_config = { + .progbufsize = 2, + .max_sba_data_width = 0, + .require_authentication = false, + .abstract_rti = 0, + .support_hasel = true, + .support_abstract_csr_access = true, + .support_abstract_fpr_access = true, + .support_haltgroups = true, + .support_impebreak = false +}; +extern std::vector> make_mems(const std::vector &layout); +extern std::vector parse_mem_layout(const char* arg); + +static DifftestRef *ref = nullptr; + +DifftestRef::DifftestRef() : + cfg(create_cfg()), + mems(make_mems(cfg->mem_layout())), +#ifdef CONFIG_DIFF_DEBUG_MODE + plugin_devices{std::make_pair(reg_t(DM_BASE_ADDR), new dummy_debug_t)}, +#else + plugin_devices{}, +#endif + sim(create_sim(cfg)), + p(sim->get_core(0UL)), + state(p->get_state()) { +} + +DifftestRef::~DifftestRef() { + delete cfg; + for (const auto& pair : mems) { + delete pair.second; + } +#ifdef CONFIG_DIFF_DEBUG_MODE + delete plugin_devices.front().second; +#endif + delete sim; +} + +void DifftestRef::step(uint64_t n) { + sim->step(n); +} + +void DifftestRef::get_regs(diff_context_t *ctx) { + for (int i = 0; i < NXPR; i++) { + ctx->gpr[i] = state->XPR[i]; + } +#ifdef CONFIG_DIFF_FPU + for (int i = 0; i < NFPR; i++) { + ctx->fpr[i] = unboxF64(state->FPR[i]); + } +#endif + ctx->pc = state->pc; + ctx->mstatus = state->mstatus->read(); + ctx->mcause = state->mcause->read(); + ctx->mepc = state->mepc->read(); + ctx->sstatus = state->sstatus->read(); + ctx->scause = state->scause->read(); + ctx->sepc = state->sepc->read(); + ctx->satp = state->satp->read(); + ctx->mip = state->mip->read(); + ctx->mie = state->mie->read(); + ctx->mscratch = state->csrmap[CSR_MSCRATCH]->read(); + ctx->sscratch = state->csrmap[CSR_SSCRATCH]->read(); + ctx->mideleg = state->mideleg->read(); + ctx->medeleg = state->medeleg->read(); + ctx->mtval = state->mtval->read(); + ctx->stval = state->stval->read(); + ctx->mtvec = state->mtvec->read(); + ctx->stvec = state->stvec->read(); + ctx->priv = state->prv; +#ifdef DIFF_DEBUG_MODE + ctx->debugMode = state->debug_mode; + ctx->dcsr = state->dcsr->read(); + ctx->dpc = state->dpc->read(); + ctx->dscratch0 = state->csrmap[CSR_DSCRATCH0]->read(); + ctx->dscratch1 = state->csrmap[CSR_DSCRATCH1]->read(); +#endif // DIFF_DEBUG_MODE +} + +void DifftestRef::set_regs(diff_context_t *ctx) { + for (int i = 0; i < NXPR; i++) { + state->XPR.write(i, ctx->gpr[i]); + } +#ifdef CONFIG_DIFF_FPU + for (int i = 0; i < NFPR; i++) { + state->FPR.write(i, freg(f64(ctx->fpr[i]))); + } +#endif + state->pc = ctx->pc; + state->mstatus->write(ctx->mstatus); + state->mcause->write(ctx->mcause); + state->mepc->write(ctx->mepc); + state->sstatus->write(ctx->sstatus); + state->scause->write(ctx->scause); + state->sepc->write(ctx->sepc); + state->satp->write(ctx->satp); + state->mip->write(ctx->mip); + state->mie->write(ctx->mie); + state->csrmap[CSR_MSCRATCH]->write(ctx->mscratch); + state->csrmap[CSR_SSCRATCH]->write(ctx->sscratch); + state->mideleg->write(ctx->mideleg); + state->medeleg->write(ctx->medeleg); + state->mtval->write(ctx->mtval); + state->stval->write(ctx->stval); + state->mtvec->write(ctx->mtvec); + state->stvec->write(ctx->stvec); + state->prv = ctx->priv; +#ifdef DIFF_DEBUG_MODE + state->debug_mode = ctx->debugMode; + state->dcsr->write(ctx->dcsr); + state->dpc->write(ctx->dpc); + state->csrmap[CSR_DSCRATCH0]->write(ctx->dscratch0); + state->csrmap[CSR_DSCRATCH1]->write(ctx->dscratch1); +#endif // DIFF_DEBUG_MODE +} + +void DifftestRef::memcpy_from_dut(reg_t dest, void* src, size_t n) { + char *base = sim->addr_to_mem(dest); + memcpy(base, src, n); +} + +void DifftestRef::debug_memcpy_from_dut(reg_t dest, void* src, size_t n) { +#ifdef CONFIG_DIFF_DEBUG_MODE + // addr is absolute physical addr + // now we are not using this right now because I don't know how spike does if from device + dummy_debug_t* dummy_debug = (dummy_debug_t *)plugin_devices.front().second; + if (!dummy_debug) { + return; + } + // start addr is virtual addr used by simulator + int offset = (dest - DM_BASE_ADDR) / sizeof(uint8_t); + uint8_t* start_addr = dummy_debug->dummy_debug_mem + offset; + memcpy(start_addr, src, n); // TODO copy to device not addr +#else +#endif +} + +void DifftestRef::raise_intr(uint64_t no) { + // Debug Intr + if (no == 0xc) { + p->halt_request = p->HR_REGULAR; + step(0); + p->halt_request = p->HR_NONE; + } else { + uint64_t mip_bit = 0x1UL << (no & 0xf); + bool is_timer_interrupt = mip_bit & 0xa0UL; + bool is_external_interrupt = mip_bit & 0xb00UL; + bool from_outside = !(mip_bit & state->mip->read()); + bool external_set = (is_timer_interrupt || is_external_interrupt) && from_outside; + if (external_set) { + state->mip->backdoor_write_with_mask(mip_bit, mip_bit); + step(1); + state->mip->backdoor_write_with_mask(mip_bit, ~mip_bit); + } else { + step(1); + } + } +} + +void DifftestRef::display() { + int i; + for (i = 0; i < 32; i ++) { + printf("%4s: " FMT_WORD " ", xpr_name[i], state->XPR[i]); + if (i % 4 == 3) { + printf("\n"); + } + } + for (i = 0; i < 32; i ++) { + printf("%4s: " FMT_WORD " ", fpr_name[i], f128_to_ui64_r_minMag(state->FPR[i], true)); + if (i % 4 == 3) { + printf("\n"); + } + } + printf("pc: " FMT_WORD " mstatus: " FMT_WORD " mcause: " FMT_WORD " mepc: " FMT_WORD "\n", + state->pc, state->mstatus->read(), state->mcause->read(), state->mepc->read()); + printf("%22s sstatus: " FMT_WORD " scause: " FMT_WORD " sepc: " FMT_WORD "\n", + "", state->sstatus->read(), state->scause->read(), state->sepc->read()); + printf("satp: " FMT_WORD "\n", state->satp->read()); + printf("mip: " FMT_WORD " mie: " FMT_WORD " mscratch: " FMT_WORD " sscratch: " FMT_WORD "\n", + state->mip->read(), state->mie->read(), state->csrmap[CSR_MSCRATCH]->read(), state->csrmap[CSR_MSCRATCH]->read()); + printf("mideleg: " FMT_WORD " medeleg: " FMT_WORD "\n", + state->mideleg->read(), state->medeleg->read()); + printf("mtval: " FMT_WORD " stval: " FMT_WORD " mtvec: " FMT_WORD " stvec: " FMT_WORD "\n", + state->mtval->read(), state->stval->read(), state->mtvec->read(), state->stvec->read()); + printf("privilege mode:%ld\n", state->prv); + fflush(stdout); +} + +const cfg_t *DifftestRef::create_cfg() { + char mem_layout_str[32]; + sprintf(mem_layout_str, "0x%x:0x%lx", DRAM_BASE, CONFIG_MEMORY_SIZE); + auto memory_layout = parse_mem_layout(mem_layout_str); + auto const cfg = new cfg_t( + // std::pair default_initrd_bounds, + std::make_pair(0, 0), + // const char *default_bootargs, + nullptr, + // const char *default_isa, + CONFIG_DIFF_ISA_STRING, + // const char *default_priv + DEFAULT_PRIV, + // const char *default_varch, + DEFAULT_VARCH, + // const bool default_misaligned, + false, + // const endianness_t default_endianness, + endianness_little, + // const reg_t default_pmpregions, + 0, + // const std::vector &default_mem_layout, + memory_layout, + // const std::vector default_hartids, + std::vector{0}, + // bool default_real_time_clint, + false, + // const reg_t default_trigger_count + 0 + ); + return cfg; +} + +sim_t *DifftestRef::create_sim(const cfg_t *cfg) { + sim_t *s = new sim_t( + // const cfg_t *cfg, + cfg, + // bool halted, + false, + // std::vector> mems + mems, + // std::vector> plugin_devices + plugin_devices, + // const std::vector& args + std::vector{}, + // const debug_module_config_t &dm_config + difftest_dm_config, + // const char *log_path +#ifndef LOG_PATH + nullptr, +#else + LOG_PATH, +#endif // LOG_PATH + //bool dtb_enabled, const char *dtb_file, bool socket_enabled, FILE *cmd_file + false, nullptr, false, nullptr + ); + + return s; +} + +// Following are the interfaces for co-simulation with other designs + +extern "C" { + +void difftest_memcpy(uint64_t addr, void *buf, size_t n, bool direction) { + if (direction == DIFFTEST_TO_REF) { + ref->memcpy_from_dut(addr, buf, n); + } else { + printf("difftest_memcpy with DIFFTEST_TO_DUT is not supported yet\n"); + fflush(stdout); + assert(0); + } +} + +void difftest_regcpy(diff_context_t* dut, bool direction) { + if (direction == DIFFTEST_TO_REF) { + ref->set_regs(dut); + } else { + ref->get_regs(dut); + } +} + +void difftest_csrcpy(void *dut, bool direction) { + +} + +void difftest_uarchstatus_cpy(void *dut, bool direction) { + +} + +void update_dynamic_config(void* config) { + ref->update_dynamic_config(config); +} + +void difftest_exec(uint64_t n) { + ref->step(n); +} + +void difftest_init(int port) { + ref = new DifftestRef; +#ifdef RISCV_ENABLE_COMMITLOG + setvbuf(p->get_log_file(), NULL, _IONBF, 0); +#endif +} + +void difftest_raise_intr(uint64_t NO) { + ref->raise_intr(NO); +} + +void isa_reg_display() { + ref->display(); +} + +int difftest_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { + return 0; +} + +uint64_t difftest_guided_exec(void *) { + ref->step(1); + return 0; +} + +void debug_mem_sync(reg_t addr, void* buf, size_t n) { + ref->debug_memcpy_from_dut(addr, buf, n); +} + +void difftest_load_flash(void *flash_bin, size_t size) { + +} + + +void difftest_close() { + delete ref; +} + +} diff --git a/difftest/difftest.h b/difftest/difftest.h new file mode 100644 index 0000000000..11650645a4 --- /dev/null +++ b/difftest/difftest.h @@ -0,0 +1,111 @@ +#ifndef __DIFFTEST_H +#define __DIFFTEST_H + +#include +#include +#include +#include + +#include "dummy_debug.h" +#include "sim.h" + +enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; +#define FMT_WORD "0x%016lx" + +# define DIFFTEST_REG_SIZE (sizeof(uint64_t) * 33) // GRPs + pc + +#ifndef DIFFTEST_LOG_FILE +#define DIFFTEST_LOG_FILE nullptr +#endif + +#if defined(CPU_NUTSHELL) +#elif defined(CPU_XIANGSHAN) +#elif defined(CPU_ROCKET_CHIP) +#else +// This is the default CPU +#define CPU_NUTSHELL +#endif + +#if defined(CPU_XIANGSHAN) || defined(CPU_ROCKET_CHIP) +#define CONFIG_DIFF_FPU +#endif + +#if defined(CPU_XIANGSHAN) +#define CONFIG_DIFF_DEBUG_MODE +#endif + +#if defined(CPU_NUTSHELL) +#define CONFIG_DIFF_ISA_STRING "rv64imaczicsr_zifencei" +#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#elif defined(CPU_XIANGSHAN) +#define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" +#define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) +#elif defined(CPU_ROCKET_CHIP) +#define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm" +#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#endif + +typedef struct { + uint64_t gpr[32]; +#ifdef CONFIG_DIFF_FPU + uint64_t fpr[32]; +#endif + uint64_t priv; + uint64_t mstatus; + uint64_t sstatus; + uint64_t mepc; + uint64_t sepc; + uint64_t mtval; + uint64_t stval; + uint64_t mtvec; + uint64_t stvec; + uint64_t mcause; + uint64_t scause; + uint64_t satp; + uint64_t mip; + uint64_t mie; + uint64_t mscratch; + uint64_t sscratch; + uint64_t mideleg; + uint64_t medeleg; + uint64_t pc; +#ifdef CONFIG_DIFF_DEBUG_MODE + uint64_t debugMode; + uint64_t dcsr; + uint64_t dpc; + uint64_t dscratch0; + uint64_t dscratch1; +#endif // CONFIG_DIFF_DEBUG_MODE +} diff_context_t; + +class DifftestRef { +public: + DifftestRef(); + ~DifftestRef(); + void step(uint64_t n); + void get_regs(diff_context_t *ctx); + void set_regs(diff_context_t *ctx); + void memcpy_from_dut(reg_t dest, void* src, size_t n); + void debug_memcpy_from_dut(reg_t dest, void* src, size_t n); + void raise_intr(uint64_t no); + void display(); + void update_dynamic_config(void* config) { +#ifdef RISCV_ENABLE_COMMITLOG + p->enable_log_commits(); +#endif + } + + +private: + const cfg_t *cfg; + const std::vector> mems; + const std::vector> plugin_devices; + sim_t * const sim; + processor_t * const p; + state_t * const state; + + const cfg_t *create_cfg(); + sim_t *create_sim(const cfg_t *cfg); +}; + +#endif diff --git a/difftest/dummy_debug.cc b/difftest/dummy_debug.cc new file mode 100644 index 0000000000..12c74c3fc4 --- /dev/null +++ b/difftest/dummy_debug.cc @@ -0,0 +1,35 @@ +#include "dummy_debug.h" +#include "sim.h" +#include "mmu.h" + +dummy_debug_t::~dummy_debug_t() +{ + +} + +bool dummy_debug_t::load(reg_t addr, size_t len, uint8_t* bytes) +{ + // addr is internal addr! + assert(addr < DM_BASE_ADDR); + assert(addr + len <= DM_END_ADDR); + int offset = addr / sizeof(uint8_t); + memcpy(bytes, &dummy_debug_mem[offset], len); + + return true; +} + +bool dummy_debug_t::store(reg_t addr, size_t len, const uint8_t* bytes) +{ + // nothing is actually stored + // because currently spike dm does not need to be working + assert(addr < DM_BASE_ADDR); + assert(addr + len <= DM_END_ADDR); + return true; +} + +// bool dummy_debug_t::update_dummy_mem(reg_t addr, size_t len, const uint8_t* bytes) +// { +// assert(addr < DM_BASE_ADDR); +// assert(addr + len <= DM_END_ADDR); +// return memcpy((void *) (addr - DM_BASE_ADDR + dummy_debug_mem), bytes, len); +// } \ No newline at end of file diff --git a/difftest/dummy_debug.h b/difftest/dummy_debug.h new file mode 100644 index 0000000000..7d26bdf5cb --- /dev/null +++ b/difftest/dummy_debug.h @@ -0,0 +1,23 @@ +#ifndef __DUMMY_DEBUG_H +#define __DUMMY_DEBUG_H + +#include "sim.h" +#include "abstract_device.h" +#include "mmu.h" + +#define DM_BASE_ADDR 0x38020000L +#define DM_END_ADDR 0x38021000L +#define DUMMY_MEM_SIZE_BYTE (DM_END_ADDR - DM_BASE_ADDR) / sizeof(uint8_t) + +class dummy_debug_t : public abstract_device_t +{ + public: + bool load(reg_t addr, size_t len, uint8_t* bytes); + bool store(reg_t addr, size_t len, const uint8_t* bytes); + ~dummy_debug_t(); + // we create a mem Region that is updated on every dut if/load/store + uint8_t dummy_debug_mem[DUMMY_MEM_SIZE_BYTE]; + bool update_dummy_mem(reg_t addr, size_t len, const uint8_t* bytes); +}; + +#endif diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 4643544cd3..05b75bc99a 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -49,32 +49,39 @@ htif_t::htif_t() tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false), syscall_proxy(this) { -#ifdef SPIKE_FUZZ +#if !defined(SPIKE_FUZZ) && !defined(DIFFTEST) signal(SIGINT, &handle_signal); signal(SIGTERM, &handle_signal); signal(SIGABRT, &handle_signal); // we still want to call static destructors -#endif // SPIKE_FUZZ +#endif } htif_t::htif_t(int argc, char** argv) : htif_t() { //Set line size as 16 by default. line_size = 16; +#ifndef DIFFTEST parse_arguments(argc, argv); +#endif register_devices(); } htif_t::htif_t(const std::vector& args) : htif_t() { + // Set line size as 16 by default. + line_size = 16; +#ifndef DIFFTEST int argc = args.size() + 1; 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); +#else + // No need for parse_arguments because the arguments are empty. + // Calling it will cause errors because of its usage of getopt. +#endif register_devices(); } diff --git a/riscv/sim.cc b/riscv/sim.cc index 500542837b..1340c3a8b6 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -59,9 +59,13 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, remote_bitbang(NULL), debug_module(this, dm_config) { - // signal(SIGINT, &handle_signal); +#if !defined(SPIKE_FUZZ) && !defined(DIFFTEST) + signal(SIGINT, &handle_signal); +#endif +#ifndef DIFFTEST sout_.rdbuf(std::cerr.rdbuf()); // debug output goes to stderr by default +#endif // DIFFTEST for (auto& x : mems) bus.add_device(x.first, x.second); diff --git a/riscv/sim.h b/riscv/sim.h index bc3ef9eb95..e63c88830e 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -35,9 +35,6 @@ class sim_t : public htif_t, public simif_t FILE *cmd_file); // needed for command line option --cmd ~sim_t(); -#ifdef SPIKE_FUZZ - void step(size_t n); // step through simulation -#endif // SPIKE_FUZZ // run the simulation to completion int run(); void set_debug(bool value); @@ -86,9 +83,13 @@ class sim_t : public htif_t, public simif_t std::ostream sout_; // used for socket and terminal interface processor_t* get_core(const std::string& i); -#ifndef SPIKE_FUZZ +#if defined(SPIKE_FUZZ) || defined(DIFFTEST) +public: +#endif void step(size_t n); // step through simulation -#endif // SPIKE_FUZZ +#if defined(SPIKE_FUZZ) || defined(DIFFTEST) +private: +#endif static const size_t INTERLEAVE = 5000; static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core static const size_t CPU_HZ = 1000000000; // 1GHz CPU @@ -101,7 +102,13 @@ class sim_t : public htif_t, public simif_t std::optional> next_interactive_action; // memory-mapped I/O routines +#if defined(DIFFTEST) +public: +#endif virtual char* addr_to_mem(reg_t paddr) override; +#if defined(DIFFTEST) +private: +#endif 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 make_dtb(const char* dtb_file); From c6f503af678b3b80dc4221f2e0312c5eeea9cd2b Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 20 Jun 2023 20:33:29 +0800 Subject: [PATCH 11/72] csrs: set mstatus.fs to 0 or 3 for CPU_ROCKET_CHIP Rocket-chip restricts the values of MSTATUS.FS. --- riscv/csrs.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 7ea07d104c..920371ef71 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -501,7 +501,15 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t requested_mpp = proc->legalize_privilege(get_field(val, MSTATUS_MPP)); const reg_t adjusted_val = set_field(val, MSTATUS_MPP, requested_mpp); +#ifdef CPU_ROCKET_CHIP + reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); + unsigned fs = (new_mstatus >> 13) & 0x3; + if (fs == 0x1 || fs == 0x2) { + new_mstatus |= 0x3 << 13; + } +#else const reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); +#endif maybe_flush_tlb(new_mstatus); this->val = adjust_sd(new_mstatus); return true; From ee71b0d26d04604a03036e7af3721e547663ef4e Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 20 Jun 2023 20:34:36 +0800 Subject: [PATCH 12/72] trap: make the tval values on insn_trap configurable rocket-chip sets the xtval to instruction values when exceptions. However, XiangShan and NutShell simply clear it, which is also compatible with the RISC-V ISA. --- riscv/trap.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/riscv/trap.h b/riscv/trap.h index 54948fdde1..cf4699615b 100644 --- a/riscv/trap.h +++ b/riscv/trap.h @@ -47,7 +47,13 @@ class insn_trap_t : public trap_t : trap_t(which), gva(gva), tval(tval) {} bool has_gva() override { return gva; } bool has_tval() override { return true; } - reg_t get_tval() override { return tval; } + reg_t get_tval() override { +#ifdef CPU_ROCKET_CHIP + return tval; +#else + return 0; +#endif + } private: bool gva; reg_t tval; From e4e73144493574f4a3130e5ad34f3758868b9456 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 21 Jun 2023 10:50:26 +0800 Subject: [PATCH 13/72] Add support for an optional flash region --- difftest/difftest.cc | 19 +++++++++++++++---- difftest/difftest.h | 7 +++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index d6b6d552b7..227d17d39b 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -16,7 +16,6 @@ static debug_module_config_t difftest_dm_config = { .support_impebreak = false }; extern std::vector> make_mems(const std::vector &layout); -extern std::vector parse_mem_layout(const char* arg); static DifftestRef *ref = nullptr; @@ -31,6 +30,15 @@ DifftestRef::DifftestRef() : sim(create_sim(cfg)), p(sim->get_core(0UL)), state(p->get_state()) { +#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) + // Initialize the flash with preset instructions + uint32_t flash_init[] = { + 0x0010029bUL, // CONFIG_FLASH_SIZE + 0: addiw t0, zero, 1 + 0x01f29293UL, // CONFIG_FLASH_SIZE + 4: slli t0, t0, 0x1f + 0x00028067UL, // CONFIG_FLASH_SIZE + 8: jr t0 + }; + memcpy_from_dut(CONFIG_FLASH_BASE, flash_init, sizeof(flash_init)); +#endif } DifftestRef::~DifftestRef() { @@ -195,9 +203,12 @@ void DifftestRef::display() { } const cfg_t *DifftestRef::create_cfg() { - char mem_layout_str[32]; - sprintf(mem_layout_str, "0x%x:0x%lx", DRAM_BASE, CONFIG_MEMORY_SIZE); - auto memory_layout = parse_mem_layout(mem_layout_str); + auto memory_layout = std::vector{ +#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) + mem_cfg_t{CONFIG_FLASH_BASE, CONFIG_FLASH_SIZE}, +#endif + mem_cfg_t{DRAM_BASE, CONFIG_MEMORY_SIZE}, + }; auto const cfg = new cfg_t( // std::pair default_initrd_bounds, std::make_pair(0, 0), diff --git a/difftest/difftest.h b/difftest/difftest.h index 11650645a4..98c4e2595d 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -34,15 +34,22 @@ enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; #define CONFIG_DIFF_DEBUG_MODE #endif + #if defined(CPU_NUTSHELL) #define CONFIG_DIFF_ISA_STRING "rv64imaczicsr_zifencei" #define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x40000000UL +#define CONFIG_FLASH_SIZE 0x1000UL #elif defined(CPU_XIANGSHAN) #define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" #define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x10000000UL +#define CONFIG_FLASH_SIZE 0x100000UL #elif defined(CPU_ROCKET_CHIP) #define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm" #define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x10000000UL +#define CONFIG_FLASH_SIZE 0x10000UL #endif typedef struct { From 8eee588ce2a9ee24ecaacaa715436d488c7a7d91 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 15:13:59 +0800 Subject: [PATCH 14/72] difftest: fix the memcpy for n > PGSIZE It seems sim_t::addr_to_mem allocates the memory of only PGSIZE bytes at every time. Therefore, we need to separate memcpy operations. --- difftest/difftest.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 227d17d39b..a554ef763d 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -131,8 +131,14 @@ void DifftestRef::set_regs(diff_context_t *ctx) { } void DifftestRef::memcpy_from_dut(reg_t dest, void* src, size_t n) { - char *base = sim->addr_to_mem(dest); - memcpy(base, src, n); + while (n) { + char *base = sim->addr_to_mem(dest); + size_t n_bytes = (n > PGSIZE) ? PGSIZE : n; + memcpy(base, src, n_bytes); + dest += PGSIZE; + src = (char *)src + PGSIZE; + n -= n_bytes; + } } void DifftestRef::debug_memcpy_from_dut(reg_t dest, void* src, size_t n) { From 3d0823e1993630b312ffd490cf0cc4dd7d8b6eda Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 15:16:22 +0800 Subject: [PATCH 15/72] mmu: update the physical address for DUTs Different DUTs may have different physical address bits. --- riscv/mmu.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/riscv/mmu.h b/riscv/mmu.h index 46c54ce88a..fb0d2916e2 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -19,7 +19,13 @@ #define PGSHIFT 12 const reg_t PGSIZE = 1 << PGSHIFT; const reg_t PGMASK = ~(PGSIZE-1); +#if defined(CPU_ROCKET_CHIP) || defined(CPU_NUTSHELL) +#define MAX_PADDR_BITS 32 +#elif defined(CPU_XIANGSHAN) +#define MAX_PADDR_BITS 36 +#else #define MAX_PADDR_BITS 56 // imposed by Sv39 / Sv48 +#endif struct insn_fetch_t { From ba31db12443b4798d5244b8c29fb87e2e0fba8d1 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 15:17:05 +0800 Subject: [PATCH 16/72] Update ASID configs for different DUTs. Both rocket-chip and NutShell do not implement ASIDs. --- riscv/encoding.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/encoding.h b/riscv/encoding.h index db7b0215b6..f71283ef42 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -245,7 +245,11 @@ #define SATP32_ASID 0x7FC00000 #define SATP32_PPN 0x003FFFFF #define SATP64_MODE 0xF000000000000000 +#if defined(CPU_ROCKET_CHIP) || defined(CPU_NUTSHELL) +#define SATP64_ASID 0x0000000000000000 +#else #define SATP64_ASID 0x0FFFF00000000000 +#endif #define SATP64_PPN 0x00000FFFFFFFFFFF #define SATP_MODE_OFF 0 From 695a596ed927813a9e2cb96cc296102f476c0bde Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 15:18:26 +0800 Subject: [PATCH 17/72] Update misa write mask for rocket-chip --- riscv/csrs.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 920371ef71..cb01ce216e 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -630,6 +630,16 @@ bool sstatus_csr_t::enabled(const reg_t which) { misa_csr_t::misa_csr_t(processor_t* const proc, const reg_t addr, const reg_t max_isa): basic_csr_t(proc, addr, max_isa), max_isa(max_isa), +#if defined(CPU_ROCKET_CHIP) + write_mask(max_isa & (0 // allow MAFDQCHV bits in MISA to be modified + | (1L << ('M' - 'A')) + | (1L << ('A' - 'A')) + | (1L << ('F' - 'A')) + | (1L << ('D' - 'A')) + | (1L << ('C' - 'A')) + | (1L << ('V' - 'A')) + ) +#else write_mask(max_isa & (0 // allow MAFDQCHV bits in MISA to be modified | (1L << ('M' - 'A')) | (1L << ('A' - 'A')) @@ -640,6 +650,7 @@ misa_csr_t::misa_csr_t(processor_t* const proc, const reg_t addr, const reg_t ma | (1L << ('H' - 'A')) | (1L << ('V' - 'A')) ) +#endif ) { } From 652026652f0de2ed579f478f59292a0385b99936 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 15:32:26 +0800 Subject: [PATCH 18/72] Update medeleg write mask for rocket-chip --- riscv/csrs.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index cb01ce216e..26e86a472e 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -893,15 +893,23 @@ void medeleg_csr_t::verify_permissions(insn_t insn, bool write) const { bool medeleg_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t mask = 0 | (1 << CAUSE_MISALIGNED_FETCH) +#if !defined(CPU_ROCKET_CHIP) | (1 << CAUSE_FETCH_ACCESS) +#endif | (1 << CAUSE_ILLEGAL_INSTRUCTION) | (1 << CAUSE_BREAKPOINT) | (1 << CAUSE_MISALIGNED_LOAD) +#if !defined(CPU_ROCKET_CHIP) | (1 << CAUSE_LOAD_ACCESS) - | (1 << CAUSE_MISALIGNED_STORE) +#endif + | (1 << CAUSE_MISALIGNED_STORE) +#if !defined(CPU_ROCKET_CHIP) | (1 << CAUSE_STORE_ACCESS) +#endif | (1 << CAUSE_USER_ECALL) +#if !defined(CPU_ROCKET_CHIP) | (1 << CAUSE_SUPERVISOR_ECALL) +#endif | (1 << CAUSE_FETCH_PAGE_FAULT) | (1 << CAUSE_LOAD_PAGE_FAULT) | (1 << CAUSE_STORE_PAGE_FAULT) From 652cfa209b683346e397e4fdb6601bc09c9c5b25 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 16:46:30 +0800 Subject: [PATCH 19/72] Change the default mmu capability to Sv39 for DUTs --- riscv/processor.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 1d5675a51a..bab8ab5a67 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -69,7 +69,11 @@ processor_t::processor_t(const isa_parser_t *isa, const cfg_t *cfg, if (isa->get_max_xlen() == 32) set_mmu_capability(IMPL_MMU_SV32); else if (isa->get_max_xlen() == 64) +#if defined(CPU_ROCKET_CHIP) || defined(CPU_NUTSHELL) || defined(CPU_XIANGSHAN) + set_mmu_capability(IMPL_MMU_SV39); +#else set_mmu_capability(IMPL_MMU_SV57); +#endif set_impl(IMPL_MMU_ASID, true); set_impl(IMPL_MMU_VMID, true); From 5f771d3bf2486f7dfbd8e15e6cfdaa59615654de Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 30 Jun 2023 16:47:30 +0800 Subject: [PATCH 20/72] Add support for difftest logs and traces We add diff_trace_t class to record Spike's actions including * instructions executed * store requests * load requests * page-table walker requests With the above information, we add support for the store commit diff. --- difftest/difftest.cc | 6 ++- difftest/difftest.h | 9 +++++ difftest/difftrace.h | 89 ++++++++++++++++++++++++++++++++++++++++++++ riscv/execute.cc | 2 + riscv/mmu.cc | 7 ++++ riscv/mmu.h | 5 +++ riscv/simif.h | 3 +- 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 difftest/difftrace.h diff --git a/difftest/difftest.cc b/difftest/difftest.cc index a554ef763d..3fc5bb5a92 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -157,6 +157,10 @@ void DifftestRef::debug_memcpy_from_dut(reg_t dest, void* src, size_t n) { #endif } +int DifftestRef::store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { + return sim->dut_store_commit(addr, data, mask); +} + void DifftestRef::raise_intr(uint64_t no) { // Debug Intr if (no == 0xc) { @@ -325,7 +329,7 @@ void isa_reg_display() { } int difftest_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { - return 0; + return ref->store_commit(addr, data, mask); } uint64_t difftest_guided_exec(void *) { diff --git a/difftest/difftest.h b/difftest/difftest.h index 98c4e2595d..45a4bc66ec 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -85,6 +85,12 @@ typedef struct { #endif // CONFIG_DIFF_DEBUG_MODE } diff_context_t; +class DifftestRefConfig { +public: + bool ignore_illegal_mem_access = false; + bool debug_difftest = false; +}; + class DifftestRef { public: DifftestRef(); @@ -94,12 +100,15 @@ class DifftestRef { void set_regs(diff_context_t *ctx); void memcpy_from_dut(reg_t dest, void* src, size_t n); void debug_memcpy_from_dut(reg_t dest, void* src, size_t n); + int store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask); void raise_intr(uint64_t no); void display(); void update_dynamic_config(void* config) { #ifdef RISCV_ENABLE_COMMITLOG p->enable_log_commits(); #endif + auto c = (DifftestRefConfig *)config; + sim->enable_difftest_logs = c->debug_difftest; } diff --git a/difftest/difftrace.h b/difftest/difftrace.h new file mode 100644 index 0000000000..95b4aee964 --- /dev/null +++ b/difftest/difftrace.h @@ -0,0 +1,89 @@ +#ifndef __DIFFTRACE_H +#define __DIFFTRACE_H + +#include +#include + +class store_trace_t { +public: + uint64_t paddr; + uint64_t data; + uint8_t mask; + + store_trace_t(uint64_t paddr, uint64_t data, uint8_t mask) : paddr(paddr), data(data), mask(mask) { + do_align(); + } + store_trace_t(uint64_t paddr, uint64_t data, int len) : paddr(paddr), data(data), mask((1U << len) - 1) { + if (len != 8) { + this->data &= (1UL << (len * 8)) - 1UL; + } + do_align(); + }; + +private: + void do_align() { + uint64_t offset = paddr % 8UL; + if (offset) { + int len = std::log2((long)mask + 1); + paddr = paddr - offset; + data &= (1UL << (len * 8)) - 1UL; + data <<= offset << 3; + mask <<= offset; + } + } +}; + +class diff_trace_t +{ +private: + std::queue store_trace; + +public: + bool enable_difftest_logs = false; + + void difftest_log(const char *__restrict __fmt, ...) { + if (unlikely(enable_difftest_logs)) { + va_list args; + va_start(args, __fmt); + fprintf(stderr, "[Spike] "); + vfprintf(stderr, __fmt, args); + fprintf(stderr, "\n"); + fflush(stderr); + va_end(args); + } + } + + void difftest_log_mem(bool is_store, uint64_t paddr, uint64_t data, int len) { + auto t = is_store ? "write" : "read"; + difftest_log("mem_%s addr: 0x%lx, data: 0x%016lx, len: %d", t, paddr, data, len); + if (is_store) { + store_trace_t trace{paddr, data, len}; + store_trace.push(trace); + } + } + + void difftest_log_mem(bool is_store, uint64_t paddr, void *data, int len) { + difftest_log_mem(is_store, paddr, *(const uint64_t *)data, len); + } + + int dut_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { + if (store_trace.empty()) { + printf("Store commit error: the store trace is empty.\n"); + return -1; + } + + store_trace_t ref = store_trace.front(); + store_trace_t dut{*addr, *data, *mask}; + if (ref.paddr != dut.paddr || ref.data != dut.data || ref.mask != dut.mask) { + *addr = ref.paddr; + *data = ref.data; + *mask = ref.mask; + return -1; + } + + store_trace.pop(); + return 0; + } +}; + +#endif diff --git a/riscv/execute.cc b/riscv/execute.cc index 295879d4db..2e1d9ffd22 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -280,6 +280,7 @@ void processor_t::step(size_t n) insn_fetch_t fetch = mmu->load_insn(pc); if (debug && !state.serialized) disasm(fetch.insn); + sim->difftest_log("pc = 0x%lx inst 0x%x", pc, fetch.insn); pc = execute_insn_logged(this, pc, fetch); advance_pc(); } @@ -289,6 +290,7 @@ void processor_t::step(size_t n) // Main simulation loop, fast path. for (auto ic_entry = _mmu->access_icache(pc); ; ) { auto fetch = ic_entry->data; + sim->difftest_log("pc = 0x%lx inst 0x%x", pc, fetch.insn); pc = execute_insn_fast(this, pc, fetch); ic_entry = ic_entry->next; if (unlikely(ic_entry->tag != pc)) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 3f90060e82..0bef4cb789 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -196,6 +196,8 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_ if (!access_info.flags.is_special_access() && vpn == (tlb_load_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) { auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; memcpy(bytes, host_addr, len); + auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; + sim->difftest_log_mem(false, paddr, host_addr, len); return; } @@ -207,6 +209,7 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_ if (auto host_addr = sim->addr_to_mem(paddr)) { memcpy(bytes, host_addr, len); + sim->difftest_log_mem(false, paddr, host_addr, len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) tracer.trace(paddr, len, LOAD); else if (!access_info.flags.is_special_access()) @@ -258,6 +261,8 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces if (actually_store) { auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; memcpy(host_addr, bytes, len); + auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; + sim->difftest_log_mem(true, paddr, host_addr, len); } return; } @@ -267,6 +272,7 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces if (actually_store) { if (auto host_addr = sim->addr_to_mem(paddr)) { memcpy(host_addr, bytes, len); + sim->difftest_log_mem(true, paddr, host_addr, len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) tracer.trace(paddr, len, STORE); else if (!access_info.flags.is_special_access()) @@ -505,6 +511,7 @@ reg_t mmu_t::walk(mem_access_info_t access_info) // check that physical address of PTE is legal auto pte_paddr = s2xlate(addr, base + idx * vm.ptesize, LOAD, type, virt, false); reg_t pte = pte_load(pte_paddr, addr, virt, type, vm.ptesize); + sim->difftest_log("ptw: level %d, vaddr 0x%lx, pg_base 0x%lx, p_pte 0x%lx, pte.val 0x%lx", i, addr, base, pte_paddr, pte); reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; bool pbmte = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_PBMTE) : (proc->get_state()->menvcfg->read() & MENVCFG_PBMTE); bool hade = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_HADE) : (proc->get_state()->menvcfg->read() & MENVCFG_HADE); diff --git a/riscv/mmu.h b/riscv/mmu.h index fb0d2916e2..b8aab12f79 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -108,6 +108,8 @@ class mmu_t if (likely(!xlate_flags.is_special_access() && aligned && tlb_hit)) { res = *(target_endian*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); + auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; + sim->difftest_log_mem(false, paddr, &res, sizeof(T)); } else { load_slow_path(addr, sizeof(T), (uint8_t*)&res, xlate_flags); } @@ -150,6 +152,9 @@ class mmu_t if (!xlate_flags.is_special_access() && likely(aligned && tlb_hit)) { *(target_endian*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); + auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; + auto v = to_target(val); + sim->difftest_log_mem(true, paddr, &v, sizeof(T)); } else { target_endian target_val = to_target(val); store_slow_path(addr, sizeof(T), (const uint8_t*)&target_val, xlate_flags, true, false); diff --git a/riscv/simif.h b/riscv/simif.h index aeab5dba77..417e331e7a 100644 --- a/riscv/simif.h +++ b/riscv/simif.h @@ -6,12 +6,13 @@ #include #include "decode.h" #include "cfg.h" +#include "difftest/difftrace.h" class processor_t; class mmu_t; // this is the interface to the simulator used by the processors and memory -class simif_t +class simif_t : public diff_trace_t { public: // should return NULL for MMIO addresses From b605d9710af119c70675772af251e4ed34d38c71 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 13:31:10 +0800 Subject: [PATCH 21/72] Add zicntr extension for rocket-chip --- difftest/difftest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/difftest/difftest.h b/difftest/difftest.h index 45a4bc66ec..9e5cb8539e 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -46,7 +46,7 @@ enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; #define CONFIG_FLASH_BASE 0x10000000UL #define CONFIG_FLASH_SIZE 0x100000UL #elif defined(CPU_ROCKET_CHIP) -#define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm" +#define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm_zicntr" #define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x10000000UL #define CONFIG_FLASH_SIZE 0x10000UL From 90679be9e626206deb4df444df775c8b783c4187 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 13:39:25 +0800 Subject: [PATCH 22/72] Move macro definitions to a separated header file --- difftest/difftest-def.h | 37 +++++++++++++++++++++++++++++++++++++ difftest/difftest.h | 35 +---------------------------------- 2 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 difftest/difftest-def.h diff --git a/difftest/difftest-def.h b/difftest/difftest-def.h new file mode 100644 index 0000000000..875a7f664d --- /dev/null +++ b/difftest/difftest-def.h @@ -0,0 +1,37 @@ +#ifndef __DIFFTEST_DEF_H +#define __DIFFTEST_DEF_H + +#if defined(CPU_NUTSHELL) +#elif defined(CPU_XIANGSHAN) +#elif defined(CPU_ROCKET_CHIP) +#else +// This is the default CPU +#define CPU_NUTSHELL +#endif + +#if defined(CPU_XIANGSHAN) || defined(CPU_ROCKET_CHIP) +#define CONFIG_DIFF_FPU +#endif + +#if defined(CPU_XIANGSHAN) +#define CONFIG_DIFF_DEBUG_MODE +#endif + +#if defined(CPU_NUTSHELL) +#define CONFIG_DIFF_ISA_STRING "rv64imaczicsr_zifencei" +#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x40000000UL +#define CONFIG_FLASH_SIZE 0x1000UL +#elif defined(CPU_XIANGSHAN) +#define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" +#define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x10000000UL +#define CONFIG_FLASH_SIZE 0x100000UL +#elif defined(CPU_ROCKET_CHIP) +#define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm_zicntr" +#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) +#define CONFIG_FLASH_BASE 0x10000000UL +#define CONFIG_FLASH_SIZE 0x10000UL +#endif + +#endif diff --git a/difftest/difftest.h b/difftest/difftest.h index 9e5cb8539e..0e73ab5fb6 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -6,6 +6,7 @@ #include #include +#include "difftest-def.h" #include "dummy_debug.h" #include "sim.h" @@ -18,40 +19,6 @@ enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; #define DIFFTEST_LOG_FILE nullptr #endif -#if defined(CPU_NUTSHELL) -#elif defined(CPU_XIANGSHAN) -#elif defined(CPU_ROCKET_CHIP) -#else -// This is the default CPU -#define CPU_NUTSHELL -#endif - -#if defined(CPU_XIANGSHAN) || defined(CPU_ROCKET_CHIP) -#define CONFIG_DIFF_FPU -#endif - -#if defined(CPU_XIANGSHAN) -#define CONFIG_DIFF_DEBUG_MODE -#endif - - -#if defined(CPU_NUTSHELL) -#define CONFIG_DIFF_ISA_STRING "rv64imaczicsr_zifencei" -#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) -#define CONFIG_FLASH_BASE 0x40000000UL -#define CONFIG_FLASH_SIZE 0x1000UL -#elif defined(CPU_XIANGSHAN) -#define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" -#define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) -#define CONFIG_FLASH_BASE 0x10000000UL -#define CONFIG_FLASH_SIZE 0x100000UL -#elif defined(CPU_ROCKET_CHIP) -#define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm_zicntr" -#define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) -#define CONFIG_FLASH_BASE 0x10000000UL -#define CONFIG_FLASH_SIZE 0x10000UL -#endif - typedef struct { uint64_t gpr[32]; #ifdef CONFIG_DIFF_FPU From b73fe6f91744f950b5ffe185173baaf74e19a99e Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 13:39:42 +0800 Subject: [PATCH 23/72] Add support for disabling AMO store diff --- difftest/difftrace.h | 13 +++++++++++-- riscv/mmu.h | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index 95b4aee964..2fbcbb2c8c 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -3,6 +3,7 @@ #include #include +#include "difftest-def.h" class store_trace_t { public: @@ -40,6 +41,7 @@ class diff_trace_t public: bool enable_difftest_logs = false; + bool is_amo = false; void difftest_log(const char *__restrict __fmt, ...) { if (unlikely(enable_difftest_logs)) { @@ -57,8 +59,15 @@ class diff_trace_t auto t = is_store ? "write" : "read"; difftest_log("mem_%s addr: 0x%lx, data: 0x%016lx, len: %d", t, paddr, data, len); if (is_store) { - store_trace_t trace{paddr, data, len}; - store_trace.push(trace); + bool do_trace = !is_amo; +#ifdef CONFIG_DIFF_AMO_STORE + do_trace = true; +#endif + if (do_trace) { + store_trace_t trace{paddr, data, len}; + store_trace.push(trace); + } + is_amo = false; } } diff --git a/riscv/mmu.h b/riscv/mmu.h index b8aab12f79..8ab0b300a8 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -190,6 +190,7 @@ class mmu_t // template for functions that perform an atomic memory operation template T amo(reg_t addr, op f) { + sim->is_amo = true; convert_load_traps_to_store_traps({ store_slow_path(addr, sizeof(T), nullptr, {false, false, false}, false, true); auto lhs = load(addr); @@ -200,6 +201,7 @@ class mmu_t template T amo_compare_and_swap(reg_t addr, T comp, T swap) { + sim->is_amo = true; convert_load_traps_to_store_traps({ store_slow_path(addr, sizeof(T), nullptr, {false, false, false}, false, true); auto lhs = load(addr); From a7ff4a277b045a33d7790833ed1cb0a79d47b50a Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 16:48:19 +0800 Subject: [PATCH 24/72] Set tval to zero on instruction misaligned exceptions Rocket-chip sets the value to zero. --- riscv/processor.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.h b/riscv/processor.h index 1b00808977..6a90544ef1 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -266,7 +266,11 @@ class processor_t : public abstract_device_t } void check_pc_alignment(reg_t pc) { if (unlikely(pc & ~pc_alignment_mask())) +#ifdef CPU_ROCKET_CHIP + throw trap_instruction_address_misaligned(state.v, 0, 0, 0); +#else throw trap_instruction_address_misaligned(state.v, pc, 0, 0); +#endif } reg_t legalize_privilege(reg_t); void set_privilege(reg_t, bool); From 9e88039aa7987e1e8eee9ea53e53207e55a8ffd0 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 18:30:55 +0800 Subject: [PATCH 25/72] Fix the missing AMO store condition for SC --- riscv/mmu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/mmu.h b/riscv/mmu.h index 8ab0b300a8..3f317af10f 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -270,6 +270,7 @@ class mmu_t template bool store_conditional(reg_t addr, T val) { + sim->is_amo = true; bool have_reservation = check_load_reservation(addr, sizeof(T)); if (have_reservation) From 45243be6364c4facd84f1957c1553f8bd8fcedf8 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 18:32:30 +0800 Subject: [PATCH 26/72] Fix the display for FPR --- difftest/difftest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 3fc5bb5a92..e8aacfa675 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -192,7 +192,7 @@ void DifftestRef::display() { } } for (i = 0; i < 32; i ++) { - printf("%4s: " FMT_WORD " ", fpr_name[i], f128_to_ui64_r_minMag(state->FPR[i], true)); + printf("%4s: " FMT_WORD " ", fpr_name[i], unboxF64(state->FPR[i])); if (i % 4 == 3) { printf("\n"); } From a490da9ef50e2f4243719e936ef2a6e4ba3c533c Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 3 Jul 2023 18:49:18 +0800 Subject: [PATCH 27/72] mmu: set is_amo before store operations Load operations may cause exceptions. The is_amo flag must be set just before the store is processed. --- riscv/mmu.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/riscv/mmu.h b/riscv/mmu.h index 3f317af10f..a271a569ea 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -190,10 +190,10 @@ class mmu_t // template for functions that perform an atomic memory operation template T amo(reg_t addr, op f) { - sim->is_amo = true; convert_load_traps_to_store_traps({ store_slow_path(addr, sizeof(T), nullptr, {false, false, false}, false, true); auto lhs = load(addr); + sim->is_amo = true; store(addr, f(lhs)); return lhs; }) @@ -201,12 +201,13 @@ class mmu_t template T amo_compare_and_swap(reg_t addr, T comp, T swap) { - sim->is_amo = true; convert_load_traps_to_store_traps({ store_slow_path(addr, sizeof(T), nullptr, {false, false, false}, false, true); auto lhs = load(addr); - if (lhs == comp) + if (lhs == comp) { + sim->is_amo = true; store(addr, swap); + } return lhs; }) } @@ -270,11 +271,12 @@ class mmu_t template bool store_conditional(reg_t addr, T val) { - sim->is_amo = true; bool have_reservation = check_load_reservation(addr, sizeof(T)); - if (have_reservation) + if (have_reservation) { + sim->is_amo = true; store(addr, val); + } yield_load_reservation(); From 14886a26747a6b1a249cf3f382952ab9ba9af840 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 4 Jul 2023 19:26:00 +0800 Subject: [PATCH 28/72] difftest: use rom_device_t for the read-only flash --- difftest/difftest.cc | 39 ++++++++++++++++++++++----------------- difftest/difftest.h | 1 + 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index e8aacfa675..e087214fcd 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -22,23 +22,10 @@ static DifftestRef *ref = nullptr; DifftestRef::DifftestRef() : cfg(create_cfg()), mems(make_mems(cfg->mem_layout())), -#ifdef CONFIG_DIFF_DEBUG_MODE - plugin_devices{std::make_pair(reg_t(DM_BASE_ADDR), new dummy_debug_t)}, -#else - plugin_devices{}, -#endif + plugin_devices(create_devices()), sim(create_sim(cfg)), p(sim->get_core(0UL)), state(p->get_state()) { -#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) - // Initialize the flash with preset instructions - uint32_t flash_init[] = { - 0x0010029bUL, // CONFIG_FLASH_SIZE + 0: addiw t0, zero, 1 - 0x01f29293UL, // CONFIG_FLASH_SIZE + 4: slli t0, t0, 0x1f - 0x00028067UL, // CONFIG_FLASH_SIZE + 8: jr t0 - }; - memcpy_from_dut(CONFIG_FLASH_BASE, flash_init, sizeof(flash_init)); -#endif } DifftestRef::~DifftestRef() { @@ -214,9 +201,6 @@ void DifftestRef::display() { const cfg_t *DifftestRef::create_cfg() { auto memory_layout = std::vector{ -#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) - mem_cfg_t{CONFIG_FLASH_BASE, CONFIG_FLASH_SIZE}, -#endif mem_cfg_t{DRAM_BASE, CONFIG_MEMORY_SIZE}, }; auto const cfg = new cfg_t( @@ -248,6 +232,27 @@ const cfg_t *DifftestRef::create_cfg() { return cfg; } +const std::vector> DifftestRef::create_devices() { +#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) + // Initialize the flash with preset instructions + const uint32_t flash_init[] = { + 0x0010029bUL, // CONFIG_FLASH_SIZE + 0: addiw t0, zero, 1 + 0x01f29293UL, // CONFIG_FLASH_SIZE + 4: slli t0, t0, 0x1f + 0x00028067UL, // CONFIG_FLASH_SIZE + 8: jr t0 + }; + std::vector rom_data((char*)flash_init, (char*)flash_init + sizeof(flash_init)); + rom_data.resize(CONFIG_FLASH_SIZE, 0); +#endif + return std::vector>{ +#ifdef CONFIG_DIFF_DEBUG_MODE + std::make_pair(reg_t(DM_BASE_ADDR), new dummy_debug_t), +#endif +#if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) + std::make_pair(reg_t(0x10000000UL), new rom_device_t(rom_data)), +#endif + }; +} + sim_t *DifftestRef::create_sim(const cfg_t *cfg) { sim_t *s = new sim_t( // const cfg_t *cfg, diff --git a/difftest/difftest.h b/difftest/difftest.h index 0e73ab5fb6..5894768828 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -88,6 +88,7 @@ class DifftestRef { state_t * const state; const cfg_t *create_cfg(); + const std::vector> create_devices(); sim_t *create_sim(const cfg_t *cfg); }; From 5be2b5f710c4ac6b2ebbc185243a6169e9c6ccce Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 5 Jul 2023 11:04:58 +0800 Subject: [PATCH 29/72] Add Sdtrig isa string with permission checkers for CSRs This commit adds the Sdtrig ISA string for the RISC-V Triggers extension with permission check for the related CSRs. --- riscv/csrs.cc | 42 ++++++++++++++++++++++++++++++++++++------ riscv/csrs.h | 34 +++++++++++++++++++++++++++++----- riscv/isa_parser.cc | 2 ++ riscv/isa_parser.h | 1 + riscv/processor.cc | 12 ++++++------ 5 files changed, 74 insertions(+), 17 deletions(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 26e86a472e..b96d8bb2d9 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1182,16 +1182,46 @@ bool hgatp_csr_t::unlogged_write(const reg_t val) noexcept { return basic_csr_t::unlogged_write((read() & ~mask) | (val & mask)); } +dtrig_csr_t::dtrig_csr_t(processor_t* const proc, const reg_t addr): + dtrig_csr_t(proc, addr, 0) { +} + +dtrig_csr_t::dtrig_csr_t(processor_t* const proc, const reg_t addr, reg_t val): + basic_csr_t(proc, addr, val) { +} + +void dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + basic_csr_t::verify_permissions(insn, write); + if (!proc->extension_enabled(EXT_SDTRIG)) + throw trap_illegal_instruction(insn.bits()); +} + +const_dtrig_csr_t::const_dtrig_csr_t(processor_t* const proc, const reg_t addr, reg_t val): + const_csr_t(proc, addr, val), dtrig(proc, addr) { +} + +void const_dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + dtrig.verify_permissions(insn, write); +} + +masked_dtrig_csr_t::masked_dtrig_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init): + masked_csr_t(proc, addr, mask, init), dtrig(proc, addr) { +} + +void masked_dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + dtrig.verify_permissions(insn, write); +} + tselect_csr_t::tselect_csr_t(processor_t* const proc, const reg_t addr): - basic_csr_t(proc, addr, 0) { + dtrig_csr_t(proc, addr, 0) { } bool tselect_csr_t::unlogged_write(const reg_t val) noexcept { - return basic_csr_t::unlogged_write((val < proc->TM.count()) ? val : read()); + return dtrig_csr_t::unlogged_write((val < proc->TM.count()) ? val : read()); } tdata1_csr_t::tdata1_csr_t(processor_t* const proc, const reg_t addr): - csr_t(proc, addr) { + dtrig_csr_t(proc, addr) { } reg_t tdata1_csr_t::read() const noexcept { @@ -1203,7 +1233,7 @@ bool tdata1_csr_t::unlogged_write(const reg_t val) noexcept { } tdata2_csr_t::tdata2_csr_t(processor_t* const proc, const reg_t addr): - csr_t(proc, addr) { + dtrig_csr_t(proc, addr) { } reg_t tdata2_csr_t::read() const noexcept { @@ -1215,7 +1245,7 @@ bool tdata2_csr_t::unlogged_write(const reg_t val) noexcept { } tdata3_csr_t::tdata3_csr_t(processor_t* const proc, const reg_t addr): - csr_t(proc, addr) { + dtrig_csr_t(proc, addr) { } reg_t tdata3_csr_t::read() const noexcept { @@ -1227,7 +1257,7 @@ bool tdata3_csr_t::unlogged_write(const reg_t val) noexcept { } tinfo_csr_t::tinfo_csr_t(processor_t* const proc, const reg_t addr) : - csr_t(proc, addr) { + dtrig_csr_t(proc, addr) { } reg_t tinfo_csr_t::read() const noexcept { diff --git a/riscv/csrs.h b/riscv/csrs.h index 07d6d82ac5..d1d37474d0 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -599,14 +599,38 @@ class hgatp_csr_t: public basic_csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; }; -class tselect_csr_t: public basic_csr_t { +// For CSRs that only exist if Sdtrig is enabled +class dtrig_csr_t: public basic_csr_t { + public: + dtrig_csr_t(processor_t* const proc, const reg_t addr); + dtrig_csr_t(processor_t* const proc, const reg_t addr, reg_t val); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class const_dtrig_csr_t: public const_csr_t { + public: + const_dtrig_csr_t(processor_t* const proc, const reg_t addr, reg_t val); + virtual void verify_permissions(insn_t insn, bool write) const override; + protected: + dtrig_csr_t dtrig; +}; + +class masked_dtrig_csr_t: public masked_csr_t { + public: + masked_dtrig_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; + protected: + dtrig_csr_t dtrig; +}; + +class tselect_csr_t: public dtrig_csr_t { public: tselect_csr_t(processor_t* const proc, const reg_t addr); protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; -class tdata1_csr_t: public csr_t { +class tdata1_csr_t: public dtrig_csr_t { public: tdata1_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override; @@ -614,7 +638,7 @@ class tdata1_csr_t: public csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; }; -class tdata2_csr_t: public csr_t { +class tdata2_csr_t: public dtrig_csr_t { public: tdata2_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override; @@ -622,7 +646,7 @@ class tdata2_csr_t: public csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; }; -class tdata3_csr_t: public csr_t { +class tdata3_csr_t: public dtrig_csr_t { public: tdata3_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override; @@ -630,7 +654,7 @@ class tdata3_csr_t: public csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; }; -class tinfo_csr_t: public csr_t { +class tinfo_csr_t: public dtrig_csr_t { public: tinfo_csr_t(processor_t* const proc, const reg_t addr); virtual reg_t read() const noexcept override; diff --git a/riscv/isa_parser.cc b/riscv/isa_parser.cc index 1c4300c958..9423efc28d 100644 --- a/riscv/isa_parser.cc +++ b/riscv/isa_parser.cc @@ -207,6 +207,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) } else if (ext_str == "zkr") { extension_table[EXT_ZKR] = true; } else if (ext_str == "zkt") { + } else if (ext_str == "sdtrig") { + extension_table[EXT_SDTRIG] = true; } else if (ext_str == "smepmp") { extension_table[EXT_SMEPMP] = true; } else if (ext_str == "smstateen") { diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index 3cbee7dea0..4e7a334b6e 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -39,6 +39,7 @@ typedef enum { EXT_ZPSFOPERAND, EXT_ZVFH, EXT_ZVFHMIN, + EXT_SDTRIG, EXT_SMEPMP, EXT_SMSTATEEN, EXT_SMRNMI, diff --git a/riscv/processor.cc b/riscv/processor.cc index bab8ab5a67..7b2699ba00 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -407,15 +407,15 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_TDATA3] = std::make_shared(proc, CSR_TDATA3); csrmap[CSR_TINFO] = std::make_shared(proc, CSR_TINFO); } else { - csrmap[CSR_TDATA1] = std::make_shared(proc, CSR_TDATA1, 0); - csrmap[CSR_TDATA2] = tdata2 = std::make_shared(proc, CSR_TDATA2, 0); - csrmap[CSR_TDATA3] = std::make_shared(proc, CSR_TDATA3, 0); - csrmap[CSR_TINFO] = std::make_shared(proc, CSR_TINFO, 0); + csrmap[CSR_TDATA1] = std::make_shared(proc, CSR_TDATA1, 0); + csrmap[CSR_TDATA2] = tdata2 = std::make_shared(proc, CSR_TDATA2, 0); + csrmap[CSR_TDATA3] = std::make_shared(proc, CSR_TDATA3, 0); + csrmap[CSR_TINFO] = std::make_shared(proc, CSR_TINFO, 0); } unsigned scontext_length = (xlen == 32 ? 16 : 34); // debug spec suggests 16-bit for RV32 and 34-bit for RV64 - csrmap[CSR_SCONTEXT] = scontext = std::make_shared(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0); + csrmap[CSR_SCONTEXT] = scontext = std::make_shared(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0); unsigned hcontext_length = (xlen == 32 ? 6 : 13) + (proc->extension_enabled('H') ? 1 : 0); // debug spec suggest 7-bit (6-bit) for RV32 and 14-bit (13-bit) for RV64 with (without) H extension - csrmap[CSR_HCONTEXT] = std::make_shared(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); + csrmap[CSR_HCONTEXT] = std::make_shared(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); csrmap[CSR_MCONTEXT] = mcontext = std::make_shared(proc, CSR_MCONTEXT, csrmap[CSR_HCONTEXT]); debug_mode = false; single_step = STEP_NONE; From e2aedc0364ead9bdd27f064382d96e2106d8cc79 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 13:29:05 +0800 Subject: [PATCH 30/72] difftrace: use Enum to wrap memory access types --- difftest/difftrace.h | 50 +++++++++++++++++++++++++++++--------------- riscv/mmu.cc | 8 +++---- riscv/mmu.h | 4 ++-- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index 2fbcbb2c8c..90eeff658f 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -39,6 +39,34 @@ class diff_trace_t private: std::queue store_trace; + enum class MemAccessType { LOAD, STORE }; + static const char *accessTypeString(MemAccessType value) { + switch (value) { + case MemAccessType::LOAD: return "load"; + case MemAccessType::STORE: return "store"; + default: return "unknown"; + } + } + + void difftest_log_mem(MemAccessType t, uint64_t paddr, uint64_t data, int len) { + difftest_log("mem_%s addr: 0x%lx, data: 0x%016lx, len: %d", accessTypeString(t), paddr, data, len); + if (t == MemAccessType::STORE) { + bool do_trace = !is_amo; +#ifdef CONFIG_DIFF_AMO_STORE + do_trace = true; +#endif + if (do_trace) { + store_trace_t trace{paddr, data, len}; + store_trace.push(trace); + } + is_amo = false; + } + } + + void difftest_log_mem(MemAccessType t, uint64_t paddr, void *data, int len) { + difftest_log_mem(t, paddr, *(const uint64_t *)data, len); + } + public: bool enable_difftest_logs = false; bool is_amo = false; @@ -55,25 +83,13 @@ class diff_trace_t } } - void difftest_log_mem(bool is_store, uint64_t paddr, uint64_t data, int len) { - auto t = is_store ? "write" : "read"; - difftest_log("mem_%s addr: 0x%lx, data: 0x%016lx, len: %d", t, paddr, data, len); - if (is_store) { - bool do_trace = !is_amo; -#ifdef CONFIG_DIFF_AMO_STORE - do_trace = true; -#endif - if (do_trace) { - store_trace_t trace{paddr, data, len}; - store_trace.push(trace); - } - is_amo = false; - } +#define __DIFFTEST_LOG_INTERFACE(name, type) \ + void inline difftest_log_mem_##name(uint64_t paddr, void *data, int len) { \ + difftest_log_mem(MemAccessType::type, paddr, *(const uint64_t *)data, len); \ } - void difftest_log_mem(bool is_store, uint64_t paddr, void *data, int len) { - difftest_log_mem(is_store, paddr, *(const uint64_t *)data, len); - } + __DIFFTEST_LOG_INTERFACE(load, LOAD) + __DIFFTEST_LOG_INTERFACE(store, STORE) int dut_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { if (store_trace.empty()) { diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 0bef4cb789..8b72af44f0 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -197,7 +197,7 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_ auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; memcpy(bytes, host_addr, len); auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; - sim->difftest_log_mem(false, paddr, host_addr, len); + sim->difftest_log_mem_load(paddr, host_addr, len); return; } @@ -209,7 +209,7 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_ if (auto host_addr = sim->addr_to_mem(paddr)) { memcpy(bytes, host_addr, len); - sim->difftest_log_mem(false, paddr, host_addr, len); + sim->difftest_log_mem_load(paddr, host_addr, len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) tracer.trace(paddr, len, LOAD); else if (!access_info.flags.is_special_access()) @@ -262,7 +262,7 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; memcpy(host_addr, bytes, len); auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; - sim->difftest_log_mem(true, paddr, host_addr, len); + sim->difftest_log_mem_store(paddr, host_addr, len); } return; } @@ -272,7 +272,7 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces if (actually_store) { if (auto host_addr = sim->addr_to_mem(paddr)) { memcpy(host_addr, bytes, len); - sim->difftest_log_mem(true, paddr, host_addr, len); + sim->difftest_log_mem_store(paddr, host_addr, len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) tracer.trace(paddr, len, STORE); else if (!access_info.flags.is_special_access()) diff --git a/riscv/mmu.h b/riscv/mmu.h index a271a569ea..d77be15c0d 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -109,7 +109,7 @@ class mmu_t if (likely(!xlate_flags.is_special_access() && aligned && tlb_hit)) { res = *(target_endian*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; - sim->difftest_log_mem(false, paddr, &res, sizeof(T)); + sim->difftest_log_mem_load(paddr, &res, sizeof(T)); } else { load_slow_path(addr, sizeof(T), (uint8_t*)&res, xlate_flags); } @@ -154,7 +154,7 @@ class mmu_t *(target_endian*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); auto paddr = tlb_data[vpn % TLB_ENTRIES].target_offset + addr; auto v = to_target(val); - sim->difftest_log_mem(true, paddr, &v, sizeof(T)); + sim->difftest_log_mem_store(paddr, &v, sizeof(T)); } else { target_endian target_val = to_target(val); store_slow_path(addr, sizeof(T), (const uint8_t*)&target_val, xlate_flags, true, false); From 72bfbefe6d63b41078bd0d3853f493b2b7da295c Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 13:37:32 +0800 Subject: [PATCH 31/72] Add support for instruction traces --- difftest/difftrace.h | 6 ++++-- riscv/mmu.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index 90eeff658f..1731208df4 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -39,9 +39,10 @@ class diff_trace_t private: std::queue store_trace; - enum class MemAccessType { LOAD, STORE }; + enum class MemAccessType { INSTRUCTION, LOAD, STORE }; static const char *accessTypeString(MemAccessType value) { switch (value) { + case MemAccessType::INSTRUCTION: return "instr"; case MemAccessType::LOAD: return "load"; case MemAccessType::STORE: return "store"; default: return "unknown"; @@ -49,7 +50,7 @@ class diff_trace_t } void difftest_log_mem(MemAccessType t, uint64_t paddr, uint64_t data, int len) { - difftest_log("mem_%s addr: 0x%lx, data: 0x%016lx, len: %d", accessTypeString(t), paddr, data, len); + difftest_log("mem_%-5s addr: 0x%lx, data: 0x%016lx, len: %d", accessTypeString(t), paddr, data, len); if (t == MemAccessType::STORE) { bool do_trace = !is_amo; #ifdef CONFIG_DIFF_AMO_STORE @@ -88,6 +89,7 @@ class diff_trace_t difftest_log_mem(MemAccessType::type, paddr, *(const uint64_t *)data, len); \ } + __DIFFTEST_LOG_INTERFACE(instr, INSTRUCTION) __DIFFTEST_LOG_INTERFACE(load, LOAD) __DIFFTEST_LOG_INTERFACE(store, STORE) diff --git a/riscv/mmu.h b/riscv/mmu.h index d77be15c0d..9e1617c41a 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -325,6 +325,7 @@ class mmu_t entry->data = fetch; reg_t paddr = tlb_entry.target_offset + addr;; + sim->difftest_log_mem_instr(paddr, &insn, sizeof(insn)); if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) { entry->tag = -1; tracer.trace(paddr, length, FETCH); From e26ab3ff303b08f5cab7fcf519222c1cef295eb5 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 17:09:05 +0800 Subject: [PATCH 32/72] Add support for forced SC failures --- difftest/difftest.cc | 4 ++-- difftest/difftest.h | 12 +++++++++++- difftest/difftrace.h | 1 + riscv/mmu.h | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index e087214fcd..75bc68f322 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -306,8 +306,8 @@ void difftest_csrcpy(void *dut, bool direction) { } -void difftest_uarchstatus_cpy(void *dut, bool direction) { - +void difftest_uarchstatus_sync(void *dut) { + ref->update_uarch_status(dut); } void update_dynamic_config(void* config) { diff --git a/difftest/difftest.h b/difftest/difftest.h index 5894768828..62d9f94b15 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -58,6 +58,11 @@ class DifftestRefConfig { bool debug_difftest = false; }; +class DifftestUarchStatus { +public: + uint64_t sc_failed = 0; +}; + class DifftestRef { public: DifftestRef(); @@ -77,7 +82,12 @@ class DifftestRef { auto c = (DifftestRefConfig *)config; sim->enable_difftest_logs = c->debug_difftest; } - + void update_uarch_status(void *status) { + auto s = (DifftestUarchStatus *)status; + if (s->sc_failed) { + sim->sc_failed = true; + } + } private: const cfg_t *cfg; diff --git a/difftest/difftrace.h b/difftest/difftrace.h index 1731208df4..6a0bda9cd0 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -71,6 +71,7 @@ class diff_trace_t public: bool enable_difftest_logs = false; bool is_amo = false; + bool sc_failed = false; void difftest_log(const char *__restrict __fmt, ...) { if (unlikely(enable_difftest_logs)) { diff --git a/riscv/mmu.h b/riscv/mmu.h index 9e1617c41a..d5e53895f9 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -272,6 +272,11 @@ class mmu_t bool store_conditional(reg_t addr, T val) { bool have_reservation = check_load_reservation(addr, sizeof(T)); + if (have_reservation && sim->sc_failed) { + sim->difftest_log("The REF is forced to have an SC failure according to the DUT."); + have_reservation = false; + sim->sc_failed = false; + } if (have_reservation) { sim->is_amo = true; From 5cd887687e5b46b966653a3f3bda7e033f04cbc0 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 17:40:15 +0800 Subject: [PATCH 33/72] Add support for REF-provided disambiguation state Only self-modified code is supported now. More cases to be added later. --- difftest/difftest.cc | 4 ++++ difftest/difftest.h | 3 +++ difftest/difftrace.h | 50 +++++++++++++++++++++++++++++++++++++++++++ riscv/insns/fence_i.h | 2 +- riscv/mmu.cc | 6 ++++++ riscv/mmu.h | 1 + 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 75bc68f322..ff15d0b67e 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -284,6 +284,10 @@ sim_t *DifftestRef::create_sim(const cfg_t *cfg) { extern "C" { +int difftest_disambiguation_state() { + return ref->disambiguation_state(); +} + void difftest_memcpy(uint64_t addr, void *buf, size_t n, bool direction) { if (direction == DIFFTEST_TO_REF) { ref->memcpy_from_dut(addr, buf, n); diff --git a/difftest/difftest.h b/difftest/difftest.h index 62d9f94b15..d357c0a10f 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -88,6 +88,9 @@ class DifftestRef { sim->sc_failed = true; } } + inline int disambiguation_state() { + return sim->has_self_modified_code(); + } private: const cfg_t *cfg; diff --git a/difftest/difftrace.h b/difftest/difftrace.h index 6a0bda9cd0..c0f5a03756 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -3,6 +3,7 @@ #include #include +#include #include "difftest-def.h" class store_trace_t { @@ -34,10 +35,41 @@ class store_trace_t { } }; +// Self-modifying code tracker +class smc_tracker_t { +public: + smc_tracker_t() : has_smc(false) {} + + inline bool state() { return has_smc; } + inline void state_reset() { has_smc = false; } + inline void reset() { + self_modified.clear(); + state_reset(); + } + inline void on_store(uint64_t address) { + self_modified.insert(hash_key(address)); + } + inline void on_fetch(uint64_t address) { + if (self_modified.count(hash_key(address)) > 0) { + has_smc = true; + } + } + +private: + bool has_smc; + std::unordered_set self_modified; + + inline uint64_t hash_key(uint64_t address) { + return address / sizeof(uint64_t); + } +}; + + class diff_trace_t { private: std::queue store_trace; + smc_tracker_t smc_tracker; enum class MemAccessType { INSTRUCTION, LOAD, STORE }; static const char *accessTypeString(MemAccessType value) { @@ -52,6 +84,7 @@ class diff_trace_t void difftest_log_mem(MemAccessType t, uint64_t paddr, uint64_t data, int len) { difftest_log("mem_%-5s addr: 0x%lx, data: 0x%016lx, len: %d", accessTypeString(t), paddr, data, len); if (t == MemAccessType::STORE) { + smc_tracker.on_store(paddr); bool do_trace = !is_amo; #ifdef CONFIG_DIFF_AMO_STORE do_trace = true; @@ -62,6 +95,9 @@ class diff_trace_t } is_amo = false; } + else if (t == MemAccessType::INSTRUCTION) { + smc_tracker.on_fetch(paddr); + } } void difftest_log_mem(MemAccessType t, uint64_t paddr, void *data, int len) { @@ -112,6 +148,20 @@ class diff_trace_t store_trace.pop(); return 0; } + + void on_fence_i() { + smc_tracker.reset(); + } + + void clear_self_modified_code_state() { + smc_tracker.state_reset(); + } + + bool has_self_modified_code() { + bool s = smc_tracker.state(); + clear_self_modified_code_state(); + return s; + } }; #endif diff --git a/riscv/insns/fence_i.h b/riscv/insns/fence_i.h index 38dcaf3fce..719ef53e43 100644 --- a/riscv/insns/fence_i.h +++ b/riscv/insns/fence_i.h @@ -1 +1 @@ -MMU.flush_icache(); +MMU.flush_icache_on_fence_i(); diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 8b72af44f0..8ec0670494 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -33,6 +33,12 @@ void mmu_t::flush_icache() icache[i].tag = -1; } +void mmu_t::flush_icache_on_fence_i() +{ + sim->on_fence_i(); + flush_icache(); +} + void mmu_t::flush_tlb() { memset(tlb_insn_tag, -1, sizeof(tlb_insn_tag)); diff --git a/riscv/mmu.h b/riscv/mmu.h index d5e53895f9..9d05f73fdf 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -354,6 +354,7 @@ class mmu_t void flush_tlb(); void flush_icache(); + void flush_icache_on_fence_i(); void register_memtracer(memtracer_t*); From f7a2914792392a36f3e1630c88cc06bc9993c04b Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 23:05:30 +0800 Subject: [PATCH 34/72] Add support for PTW's ambiguation states PTE stores may not take effect before sfence.vma. --- difftest/difftest.h | 2 +- difftest/difftrace.h | 54 ++++++++++++++++++++++++++++---------------- riscv/mmu.cc | 6 +++++ riscv/mmu.h | 2 ++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/difftest/difftest.h b/difftest/difftest.h index d357c0a10f..1035a5fecc 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -89,7 +89,7 @@ class DifftestRef { } } inline int disambiguation_state() { - return sim->has_self_modified_code(); + return sim->in_ambiguation_state(); } private: diff --git a/difftest/difftrace.h b/difftest/difftrace.h index c0f5a03756..e92c1d9e6d 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -35,31 +35,31 @@ class store_trace_t { } }; -// Self-modifying code tracker -class smc_tracker_t { +class store_tracker_t { public: - smc_tracker_t() : has_smc(false) {} + store_tracker_t() : dirty_accessed(false) {} - inline bool state() { return has_smc; } - inline void state_reset() { has_smc = false; } + inline bool state() { return dirty_accessed; } + inline void state_reset() { dirty_accessed = false; } inline void reset() { - self_modified.clear(); + dirty.clear(); state_reset(); } inline void on_store(uint64_t address) { - self_modified.insert(hash_key(address)); + dirty.insert(hash_key(address)); } - inline void on_fetch(uint64_t address) { - if (self_modified.count(hash_key(address)) > 0) { - has_smc = true; + inline void on_read(uint64_t address) { + if (dirty.count(hash_key(address)) > 0) { + dirty_accessed = true; } } private: - bool has_smc; - std::unordered_set self_modified; + bool dirty_accessed; + std::unordered_set dirty; - inline uint64_t hash_key(uint64_t address) { +protected: + inline virtual uint64_t hash_key(uint64_t address) { return address / sizeof(uint64_t); } }; @@ -69,14 +69,18 @@ class diff_trace_t { private: std::queue store_trace; - smc_tracker_t smc_tracker; + // self-modified code. fence.i is the barrier + store_tracker_t smc_tracker; + // pte access. sfence.vma is the barrier + store_tracker_t pte_tracker; - enum class MemAccessType { INSTRUCTION, LOAD, STORE }; + enum class MemAccessType { INSTRUCTION, LOAD, STORE, PTW }; static const char *accessTypeString(MemAccessType value) { switch (value) { case MemAccessType::INSTRUCTION: return "instr"; case MemAccessType::LOAD: return "load"; case MemAccessType::STORE: return "store"; + case MemAccessType::PTW: return "ptw"; default: return "unknown"; } } @@ -85,6 +89,7 @@ class diff_trace_t difftest_log("mem_%-5s addr: 0x%lx, data: 0x%016lx, len: %d", accessTypeString(t), paddr, data, len); if (t == MemAccessType::STORE) { smc_tracker.on_store(paddr); + pte_tracker.on_store(paddr); bool do_trace = !is_amo; #ifdef CONFIG_DIFF_AMO_STORE do_trace = true; @@ -96,7 +101,10 @@ class diff_trace_t is_amo = false; } else if (t == MemAccessType::INSTRUCTION) { - smc_tracker.on_fetch(paddr); + smc_tracker.on_read(paddr); + } + else if (t == MemAccessType::PTW) { + pte_tracker.on_read(paddr); } } @@ -129,6 +137,7 @@ class diff_trace_t __DIFFTEST_LOG_INTERFACE(instr, INSTRUCTION) __DIFFTEST_LOG_INTERFACE(load, LOAD) __DIFFTEST_LOG_INTERFACE(store, STORE) + __DIFFTEST_LOG_INTERFACE(ptw, PTW) int dut_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { if (store_trace.empty()) { @@ -153,13 +162,18 @@ class diff_trace_t smc_tracker.reset(); } - void clear_self_modified_code_state() { + void on_sfence_vma() { + pte_tracker.reset(); + } + + void clear_ambiguation_state() { smc_tracker.state_reset(); + pte_tracker.state_reset(); } - bool has_self_modified_code() { - bool s = smc_tracker.state(); - clear_self_modified_code_state(); + bool in_ambiguation_state() { + bool s = smc_tracker.state() || pte_tracker.state(); + clear_ambiguation_state(); return s; } }; diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 8ec0670494..4fa739cd82 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -48,6 +48,12 @@ void mmu_t::flush_tlb() flush_icache(); } +void mmu_t::flush_tlb_on_sfence_vma() +{ + sim->on_sfence_vma(); + flush_tlb(); +} + void throw_access_exception(bool virt, reg_t addr, access_type type) { switch (type) { diff --git a/riscv/mmu.h b/riscv/mmu.h index 9d05f73fdf..9a36667dfc 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -353,6 +353,7 @@ class mmu_t } void flush_tlb(); + void flush_tlb_on_sfence_vma(); void flush_icache(); void flush_icache_on_fence_i(); @@ -453,6 +454,7 @@ class mmu_t target_endian target_pte; if (host_pte_addr) { memcpy(&target_pte, host_pte_addr, ptesize); + sim->difftest_log_mem_ptw(pte_paddr, host_pte_addr, ptesize); } else if (!mmio_load(pte_paddr, ptesize, (uint8_t*)&target_pte)) { throw_access_exception(virt, addr, trap_type); } From 537386148174b982433d64a16db4e8550332e4a0 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 7 Jul 2023 23:30:27 +0800 Subject: [PATCH 35/72] Add support for ambiguation after satp is updated According to the RISC-V manual, writing satp does not imply any ordering constraints between page-table updates and subsequent address translations. Therefore, we track the status of satp write and sfence.vma. If satp is written and changes from Bare mode to Sv39, we marks it as an ambiguation state. Note that the satp_written is too coarse-grained and must be optimized in the future. --- difftest/difftrace.h | 14 +++++++++++++- riscv/csrs.cc | 7 +++++-- riscv/mmu.cc | 6 ++++++ riscv/mmu.h | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index e92c1d9e6d..eb9ec5ae03 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -73,6 +73,10 @@ class diff_trace_t store_tracker_t smc_tracker; // pte access. sfence.vma is the barrier store_tracker_t pte_tracker; + // Writing satp does not imply any ordering constraints between + // page-table updates and subsequent address translations. + // Note: satp_written is too coarse-grained and must be optimized in the future. + bool satp_written = false; enum class MemAccessType { INSTRUCTION, LOAD, STORE, PTW }; static const char *accessTypeString(MemAccessType value) { @@ -164,15 +168,23 @@ class diff_trace_t void on_sfence_vma() { pte_tracker.reset(); + satp_written = false; + } + + void on_satp_update(bool is_safe) { + if (!is_safe) { + satp_written = true; + } } void clear_ambiguation_state() { smc_tracker.state_reset(); pte_tracker.state_reset(); + satp_written = false; } bool in_ambiguation_state() { - bool s = smc_tracker.state() || pte_tracker.state(); + bool s = smc_tracker.state() || pte_tracker.state() || satp_written; clear_ambiguation_state(); return s; } diff --git a/riscv/csrs.cc b/riscv/csrs.cc index b96d8bb2d9..df07a23d52 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -941,8 +941,11 @@ base_atp_csr_t::base_atp_csr_t(processor_t* const proc, const reg_t addr): bool base_atp_csr_t::unlogged_write(const reg_t val) noexcept { const reg_t newval = proc->supports_impl(IMPL_MMU) ? compute_new_satp(val) : 0; - if (newval != read()) - proc->get_mmu()->flush_tlb(); + if (newval != read()) { + // It should be safe to change from Bare mode (no translation) + bool is_safe = get_field(read(), SATP64_MODE) == SATP_MODE_OFF; + proc->get_mmu()->flush_tlb_on_satp_update(is_safe); + } return basic_csr_t::unlogged_write(newval); } diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 4fa739cd82..89be547313 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -54,6 +54,12 @@ void mmu_t::flush_tlb_on_sfence_vma() flush_tlb(); } +void mmu_t::flush_tlb_on_satp_update(bool is_safe) +{ + sim->on_satp_update(is_safe); + flush_tlb(); +} + void throw_access_exception(bool virt, reg_t addr, access_type type) { switch (type) { diff --git a/riscv/mmu.h b/riscv/mmu.h index 9a36667dfc..1fdd0d5d99 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -354,6 +354,7 @@ class mmu_t void flush_tlb(); void flush_tlb_on_sfence_vma(); + void flush_tlb_on_satp_update(bool is_safe); void flush_icache(); void flush_icache_on_fence_i(); From 3e89f4113f29057689f194f989baa8812b1778e7 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 9 Jul 2023 14:47:58 +0800 Subject: [PATCH 36/72] store_tracker: check the next position if needed --- difftest/difftrace.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index eb9ec5ae03..a93b478caa 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -49,7 +49,8 @@ class store_tracker_t { dirty.insert(hash_key(address)); } inline void on_read(uint64_t address) { - if (dirty.count(hash_key(address)) > 0) { + auto key = hash_key(address); + if (dirty.count(key) > 0 || (check_next(address) && dirty.count(key + 1) > 0)) { dirty_accessed = true; } } @@ -62,6 +63,9 @@ class store_tracker_t { inline virtual uint64_t hash_key(uint64_t address) { return address / sizeof(uint64_t); } + inline virtual bool check_next(uint64_t address) { + return address % sizeof(uint64_t); + } }; From bf196f53d9152b5616f113443c48b1af79e68865 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 10 Jul 2023 11:30:21 +0800 Subject: [PATCH 37/72] csrs: align the behaviors of epc with rocket-chip --- riscv/csrs.cc | 10 ++++++++++ riscv/processor.cc | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index df07a23d52..ea7348064a 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -355,11 +355,21 @@ epc_csr_t::epc_csr_t(processor_t* const proc, const reg_t addr): } reg_t epc_csr_t::read() const noexcept { +#ifdef CPU_ROCKET_CHIP + uint64_t r = this->val & proc->pc_alignment_mask(); + uint64_t hi = ((r >> 39) & 0x1) ? -1UL : 0; + uint64_t mask = (1UL << 40) - 1; + return (r & mask) | (hi & (~mask)); +#else return val & proc->pc_alignment_mask(); +#endif } bool epc_csr_t::unlogged_write(const reg_t val) noexcept { this->val = val & ~(reg_t)1; +#ifdef CPU_ROCKET_CHIP + this->val &= (1UL << 40) - 1; +#endif return true; } diff --git a/riscv/processor.cc b/riscv/processor.cc index 7b2699ba00..7f834d8db6 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -772,6 +772,16 @@ void processor_t::debug_output_log(std::stringstream *s) } } +static uint64_t encode_vaddr(uint64_t vaddr) { + int64_t hi = (int64_t)vaddr >> 39; + if (hi == 0 || hi == -1) { + return vaddr; + } + hi = ((vaddr >> 38) & 0x1) ? 0 : -1; + uint64_t mask = (1UL << 39) - 1; + return (vaddr & mask) | (hi & (~mask)); +} + void processor_t::take_trap(trap_t& t, reg_t epc) { unsigned max_xlen = isa->get_max_xlen(); @@ -815,7 +825,11 @@ void processor_t::take_trap(trap_t& t, reg_t epc) reg_t vector = (state.vstvec->read() & 1) && interrupt ? 4 * bit : 0; state.pc = (state.vstvec->read() & ~(reg_t)1) + vector; state.vscause->write((interrupt) ? (t.cause() - 1) : t.cause()); +#ifdef CPU_ROCKET_CHIP + state.vsepc->write(encode_vaddr(epc)); +#else state.vsepc->write(epc); +#endif state.vstval->write(t.get_tval()); reg_t s = state.sstatus->read(); @@ -829,7 +843,11 @@ void processor_t::take_trap(trap_t& t, reg_t epc) reg_t vector = (state.nonvirtual_stvec->read() & 1) && interrupt ? 4 * bit : 0; state.pc = (state.nonvirtual_stvec->read() & ~(reg_t)1) + vector; state.nonvirtual_scause->write(t.cause()); +#ifdef CPU_ROCKET_CHIP + state.nonvirtual_sepc->write(encode_vaddr(epc)); +#else state.nonvirtual_sepc->write(epc); +#endif state.nonvirtual_stval->write(t.get_tval()); state.htval->write(t.get_tval2()); state.htinst->write(t.get_tinst()); @@ -857,7 +875,11 @@ void processor_t::take_trap(trap_t& t, reg_t epc) const reg_t rnmi_trap_handler_address = 0; const bool nmie = !(state.mnstatus && !get_field(state.mnstatus->read(), MNSTATUS_NMIE)); state.pc = !nmie ? rnmi_trap_handler_address : trap_handler_address; +#ifdef CPU_ROCKET_CHIP + state.mepc->write(encode_vaddr(epc)); +#else state.mepc->write(epc); +#endif state.mcause->write(t.cause()); state.mtval->write(t.get_tval()); state.mtval2->write(t.get_tval2()); From d3c00878851890669f6f310f73cf37c628c3d461 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 13 Jul 2023 15:31:50 +0800 Subject: [PATCH 38/72] difftest: fix the memory leak on plugin_devices --- difftest/difftest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index ff15d0b67e..b08cbb2c5b 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -33,9 +33,9 @@ DifftestRef::~DifftestRef() { for (const auto& pair : mems) { delete pair.second; } -#ifdef CONFIG_DIFF_DEBUG_MODE - delete plugin_devices.front().second; -#endif + for (const auto& pair : plugin_devices) { + delete pair.second; + } delete sim; } From afef448970b634773276a6393722c10e4b5ae7b5 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 13 Jul 2023 15:51:44 +0800 Subject: [PATCH 39/72] difftest: fix the flash base address --- difftest/difftest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index b08cbb2c5b..40e743efcc 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -248,7 +248,7 @@ const std::vector> DifftestRef::create_devi std::make_pair(reg_t(DM_BASE_ADDR), new dummy_debug_t), #endif #if defined(CONFIG_FLASH_BASE) && defined(CONFIG_FLASH_SIZE) - std::make_pair(reg_t(0x10000000UL), new rom_device_t(rom_data)), + std::make_pair(reg_t(CONFIG_FLASH_BASE), new rom_device_t(rom_data)), #endif }; } From bea82f174839b099e0efd8c8db3b3b9e8519028a Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 13 Jul 2023 16:14:10 +0800 Subject: [PATCH 40/72] csr,tvec: mode is non-writable for CPU_NUTSHELL --- riscv/csrs.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index ea7348064a..8e40ce59a3 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -384,7 +384,11 @@ reg_t tvec_csr_t::read() const noexcept { } bool tvec_csr_t::unlogged_write(const reg_t val) noexcept { +#if defined(CPU_NUTSHELL) + this->val = val & ~(reg_t)3; +#else this->val = val & ~(reg_t)2; +#endif return true; } From 6dda26986367877d9a51dd61c16a4921d0c84962 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 13 Jul 2023 21:08:04 +0800 Subject: [PATCH 41/72] proc: fix the counteren_mask for rocket-chip --- riscv/processor.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 7f834d8db6..12576381c1 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -332,7 +332,11 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_MEDELEG] = medeleg = std::make_shared(proc, CSR_MEDELEG); csrmap[CSR_MIDELEG] = mideleg = std::make_shared(proc, CSR_MIDELEG); +#ifdef CPU_ROCKET_CHIP + const reg_t counteren_mask = (proc->extension_enabled_const(EXT_ZICNTR) ? 0x7UL : 0x0); +#else const reg_t counteren_mask = (proc->extension_enabled_const(EXT_ZICNTR) ? 0x7UL : 0x0) | (proc->extension_enabled_const(EXT_ZIHPM) ? 0xfffffff8ULL : 0x0); +#endif mcounteren = std::make_shared(proc, CSR_MCOUNTEREN, counteren_mask, 0); if (proc->extension_enabled_const('U')) csrmap[CSR_MCOUNTEREN] = mcounteren; csrmap[CSR_SCOUNTEREN] = scounteren = std::make_shared(proc, CSR_SCOUNTEREN, counteren_mask, 0); From 8586b05814f041d25a60e6da529f07933eaf5737 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 14 Jul 2023 14:50:55 +0800 Subject: [PATCH 42/72] mmu: clear sc_failed after check_load_reservation This should avoid the previous instructions' state polluting the following instructions. --- riscv/mmu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/mmu.h b/riscv/mmu.h index 1fdd0d5d99..8f16f6e8b7 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -275,8 +275,8 @@ class mmu_t if (have_reservation && sim->sc_failed) { sim->difftest_log("The REF is forced to have an SC failure according to the DUT."); have_reservation = false; - sim->sc_failed = false; } + sim->sc_failed = false; if (have_reservation) { sim->is_amo = true; From 06458b085fb808f08739025a8a17ab55829590d9 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 14 Jul 2023 20:47:40 +0800 Subject: [PATCH 43/72] difftest: add on_demand option to regcpy --- difftest/difftest.cc | 110 +++++++++++++++++++++++++++++++------------ difftest/difftest.h | 2 +- 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 40e743efcc..8ad364c9e6 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -80,40 +80,92 @@ void DifftestRef::get_regs(diff_context_t *ctx) { #endif // DIFF_DEBUG_MODE } -void DifftestRef::set_regs(diff_context_t *ctx) { +void DifftestRef::set_regs(diff_context_t *ctx, bool on_demand) { for (int i = 0; i < NXPR; i++) { - state->XPR.write(i, ctx->gpr[i]); + if (!on_demand || state->XPR[i] != ctx->gpr[i]) { + state->XPR.write(i, ctx->gpr[i]); + } } #ifdef CONFIG_DIFF_FPU for (int i = 0; i < NFPR; i++) { - state->FPR.write(i, freg(f64(ctx->fpr[i]))); + if (!on_demand || unboxF64(state->FPR[i]) != ctx->fpr[i]) { + state->FPR.write(i, freg(f64(ctx->fpr[i]))); + } } #endif - state->pc = ctx->pc; - state->mstatus->write(ctx->mstatus); - state->mcause->write(ctx->mcause); - state->mepc->write(ctx->mepc); - state->sstatus->write(ctx->sstatus); - state->scause->write(ctx->scause); - state->sepc->write(ctx->sepc); - state->satp->write(ctx->satp); - state->mip->write(ctx->mip); - state->mie->write(ctx->mie); - state->csrmap[CSR_MSCRATCH]->write(ctx->mscratch); - state->csrmap[CSR_SSCRATCH]->write(ctx->sscratch); - state->mideleg->write(ctx->mideleg); - state->medeleg->write(ctx->medeleg); - state->mtval->write(ctx->mtval); - state->stval->write(ctx->stval); - state->mtvec->write(ctx->mtvec); - state->stvec->write(ctx->stvec); - state->prv = ctx->priv; + if (!on_demand || state->pc != ctx->pc) { + state->pc = ctx->pc; + } + if (!on_demand || state->mstatus->read() != ctx->pc) { + state->mstatus->write(ctx->mstatus); + } + if (!on_demand || state->mcause->read() != ctx->mcause) { + state->mcause->write(ctx->mcause); + } + if (!on_demand || state->mepc->read() != ctx->mepc) { + state->mepc->write(ctx->mepc); + } + if (!on_demand || state->sstatus->read() != ctx->sstatus) { + state->sstatus->write(ctx->sstatus); + } + if (!on_demand || state->scause->read() != ctx->scause) { + state->scause->write(ctx->scause); + } + if (!on_demand || state->sepc->read() != ctx->sepc) { + state->sepc->write(ctx->sepc); + } + if (!on_demand || state->satp->read() != ctx->satp) { + state->satp->write(ctx->satp); + } + if (!on_demand || state->mip->read() != ctx->mip) { + state->mip->write(ctx->mip); + } + if (!on_demand || state->mie->read() != ctx->mie) { + state->mie->write(ctx->mie); + } + if (!on_demand || state->csrmap[CSR_MSCRATCH]->read() != ctx->mscratch) { + state->csrmap[CSR_MSCRATCH]->write(ctx->mscratch); + } + if (!on_demand || state->csrmap[CSR_SSCRATCH]->read() != ctx->sscratch) { + state->csrmap[CSR_SSCRATCH]->write(ctx->sscratch); + } + if (!on_demand || state->mideleg->read() != ctx->mideleg) { + state->mideleg->write(ctx->mideleg); + } + if (!on_demand || state->medeleg->read() != ctx->medeleg) { + state->medeleg->write(ctx->medeleg); + } + if (!on_demand || state->mtval->read() != ctx->mtval) { + state->mtval->write(ctx->mtval); + } + if (!on_demand || state->stval->read() != ctx->stval) { + state->stval->write(ctx->stval); + } + if (!on_demand || state->mtvec->read() != ctx->mtvec) { + state->mtvec->write(ctx->mtvec); + } + if (!on_demand || state->stvec->read() != ctx->stvec) { + state->stvec->write(ctx->stvec); + } + if (!on_demand || state->prv != ctx->priv) { + state->prv = ctx->priv; + } #ifdef DIFF_DEBUG_MODE - state->debug_mode = ctx->debugMode; - state->dcsr->write(ctx->dcsr); - state->dpc->write(ctx->dpc); - state->csrmap[CSR_DSCRATCH0]->write(ctx->dscratch0); - state->csrmap[CSR_DSCRATCH1]->write(ctx->dscratch1); + if (!on_demand || state->debug_mode->read() != ctx->debugMode) { + state->debug_mode = ctx->debugMode; + } + if (!on_demand || state->dcsr->read() != ctx->dcsr) { + state->dcsr->write(ctx->dcsr); + } + if (!on_demand || state->dpc->read() != ctx->dpc) { + state->dpc->write(ctx->dpc); + } + if (!on_demand || state->csrmap[CSR_DSCRATCH0]->read() != ctx->dscratch0) { + state->csrmap[CSR_DSCRATCH0]->write(ctx->dscratch0); + } + if (!on_demand || state->csrmap[CSR_DSCRATCH1]->read() != ctx->dscratch1) { + state->csrmap[CSR_DSCRATCH1]->write(ctx->dscratch1); + } #endif // DIFF_DEBUG_MODE } @@ -298,9 +350,9 @@ void difftest_memcpy(uint64_t addr, void *buf, size_t n, bool direction) { } } -void difftest_regcpy(diff_context_t* dut, bool direction) { +void difftest_regcpy(diff_context_t* dut, bool direction, bool on_demand) { if (direction == DIFFTEST_TO_REF) { - ref->set_regs(dut); + ref->set_regs(dut, on_demand); } else { ref->get_regs(dut); } diff --git a/difftest/difftest.h b/difftest/difftest.h index 1035a5fecc..03db6c1d8d 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -69,7 +69,7 @@ class DifftestRef { ~DifftestRef(); void step(uint64_t n); void get_regs(diff_context_t *ctx); - void set_regs(diff_context_t *ctx); + void set_regs(diff_context_t *ctx, bool on_demand); void memcpy_from_dut(reg_t dest, void* src, size_t n); void debug_memcpy_from_dut(reg_t dest, void* src, size_t n); int store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask); From 3d431b6b40c98c2e12738e223087d5205ca2a43e Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 14 Jul 2023 20:48:06 +0800 Subject: [PATCH 44/72] proc: fix the IALIGN for RVC Spike uses ZCA to determine IALIGN, whereas rocket-chip uses misa['C']. Don't know which is correct. RISC-V is fragmented. --- riscv/processor.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.h b/riscv/processor.h index 6a90544ef1..437dd42dac 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -261,7 +261,11 @@ class processor_t : public abstract_device_t return impl_table[impl]; } reg_t pc_alignment_mask() { +#ifdef CPU_ROCKET_CHIP + const int ialign = extension_enabled('C') ? 16 : 32; +#else const int ialign = extension_enabled(EXT_ZCA) ? 16 : 32; +#endif return ~(reg_t)(ialign == 16 ? 0 : 2); } void check_pc_alignment(reg_t pc) { From ebfdc676f36d7de112a59a657a5f099b688dd988 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 14 Jul 2023 20:49:18 +0800 Subject: [PATCH 45/72] Update marchid for rocket-chip --- riscv/processor.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 12576381c1..1e24613ccc 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -441,7 +441,11 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_SEED] = std::make_shared(proc, CSR_SEED); +#ifdef CPU_ROCKET_CHIP + csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 1); +#else csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 5); +#endif csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); csrmap[CSR_MVENDORID] = std::make_shared(proc, CSR_MVENDORID, 0); csrmap[CSR_MHARTID] = std::make_shared(proc, CSR_MHARTID, proc->get_id()); From 17ca299b5ea7cf09d883e8c1515cdd66249b5910 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 14 Jul 2023 20:49:50 +0800 Subject: [PATCH 46/72] Disable time CSR in difftest mode --- riscv/processor.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 1e24613ccc..d4da2d3970 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -227,7 +227,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) if (proc->extension_enabled_const(EXT_ZICNTR)) { csrmap[CSR_INSTRET] = std::make_shared(proc, CSR_INSTRET, minstret); csrmap[CSR_CYCLE] = std::make_shared(proc, CSR_CYCLE, mcycle); +#ifndef DIFFTEST csrmap[CSR_TIME] = time_proxy = std::make_shared(proc, CSR_TIME, time); +#endif } if (xlen == 32) { csr_t_p minstreth, mcycleh; @@ -239,7 +241,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) auto timeh = std::make_shared(proc, CSR_TIMEH, time); csrmap[CSR_INSTRETH] = std::make_shared(proc, CSR_INSTRETH, minstreth); csrmap[CSR_CYCLEH] = std::make_shared(proc, CSR_CYCLEH, mcycleh); +#ifndef DIFFTEST csrmap[CSR_TIMEH] = std::make_shared(proc, CSR_TIMEH, timeh); +#endif } } else { csrmap[CSR_MINSTRET] = minstret; From 8a882b4e67435721eed60853ff9cdea0d2bac5a9 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sat, 15 Jul 2023 10:53:40 +0800 Subject: [PATCH 47/72] csrs: fix the permissions of mcontext This CSR only exists if Sdtrig is enabled. --- riscv/csrs.cc | 11 +++++++++++ riscv/csrs.h | 8 ++++++++ riscv/processor.cc | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 8e40ce59a3..80847b0dae 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1218,6 +1218,7 @@ const_dtrig_csr_t::const_dtrig_csr_t(processor_t* const proc, const reg_t addr, } void const_dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + const_csr_t::verify_permissions(insn, write); dtrig.verify_permissions(insn, write); } @@ -1226,6 +1227,16 @@ masked_dtrig_csr_t::masked_dtrig_csr_t(processor_t* const proc, const reg_t addr } void masked_dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + masked_csr_t::verify_permissions(insn, write); + dtrig.verify_permissions(insn, write); +} + +proxy_dtrig_csr_t::proxy_dtrig_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate): + proxy_csr_t(proc, addr, delegate), dtrig(proc, addr) { +} + +void proxy_dtrig_csr_t::verify_permissions(insn_t insn, bool write) const { + proxy_csr_t::verify_permissions(insn, write); dtrig.verify_permissions(insn, write); } diff --git a/riscv/csrs.h b/riscv/csrs.h index d1d37474d0..0e4633eaa3 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -623,6 +623,14 @@ class masked_dtrig_csr_t: public masked_csr_t { dtrig_csr_t dtrig; }; +class proxy_dtrig_csr_t: public proxy_csr_t { + public: + proxy_dtrig_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate); + virtual void verify_permissions(insn_t insn, bool write) const override; + protected: + dtrig_csr_t dtrig; +}; + class tselect_csr_t: public dtrig_csr_t { public: tselect_csr_t(processor_t* const proc, const reg_t addr); diff --git a/riscv/processor.cc b/riscv/processor.cc index d4da2d3970..587bc73905 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -424,7 +424,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_SCONTEXT] = scontext = std::make_shared(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0); unsigned hcontext_length = (xlen == 32 ? 6 : 13) + (proc->extension_enabled('H') ? 1 : 0); // debug spec suggest 7-bit (6-bit) for RV32 and 14-bit (13-bit) for RV64 with (without) H extension csrmap[CSR_HCONTEXT] = std::make_shared(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); - csrmap[CSR_MCONTEXT] = mcontext = std::make_shared(proc, CSR_MCONTEXT, csrmap[CSR_HCONTEXT]); + csrmap[CSR_MCONTEXT] = mcontext = std::make_shared(proc, CSR_MCONTEXT, csrmap[CSR_HCONTEXT]); debug_mode = false; single_step = STEP_NONE; From 2e64f66d8bb5c71c5457dff42cf24bcde5e49fb5 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sat, 15 Jul 2023 10:55:22 +0800 Subject: [PATCH 48/72] processor: fix the mimpid for rocket-chip --- riscv/processor.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 587bc73905..9041d0f94c 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -447,10 +447,11 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) #ifdef CPU_ROCKET_CHIP csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 1); + csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0x20181004); #else csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 5); -#endif csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); +#endif csrmap[CSR_MVENDORID] = std::make_shared(proc, CSR_MVENDORID, 0); csrmap[CSR_MHARTID] = std::make_shared(proc, CSR_MHARTID, proc->get_id()); csrmap[CSR_MCONFIGPTR] = std::make_shared(proc, CSR_MCONFIGPTR, 0); From 32516bd9d5f50b9fab96c28871eb3f990f584dca Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sat, 15 Jul 2023 11:03:36 +0800 Subject: [PATCH 49/72] sim: disable routine timer update for DiffTest --- riscv/sim.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv/sim.h b/riscv/sim.h index e63c88830e..881d6ebdb3 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -89,8 +89,10 @@ class sim_t : public htif_t, public simif_t void step(size_t n); // step through simulation #if defined(SPIKE_FUZZ) || defined(DIFFTEST) private: -#endif + static const size_t INTERLEAVE = -1ULL; // disable the timer +#else static const size_t INTERLEAVE = 5000; +#endif static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core static const size_t CPU_HZ = 1000000000; // 1GHz CPU size_t current_step; From 552126d8cf2d949650808b7ecf6f5c4682a76af1 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 18 Jul 2023 10:57:29 +0800 Subject: [PATCH 50/72] mmu: fix the order of bytes on instruction fetch --- riscv/mmu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/riscv/mmu.h b/riscv/mmu.h index 8f16f6e8b7..307a31cd2c 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -315,13 +315,13 @@ class mmu_t } else if (length == 2) { // entire instruction already fetched } else if (length == 6) { - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 2)) << 16; + insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; } else { static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t"); - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 6)) << 48; - insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 2)) << 16; + insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 4)) << 32; + insn |= (insn_bits_t)from_le(*(const uint16_t*)translate_insn_addr_to_host(addr + 6)) << 48; } insn_fetch_t fetch = {proc->decode_insn(insn), insn}; From 619bc4853b541105c14b90e3e48f987121b41733 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 18 Jul 2023 11:09:09 +0800 Subject: [PATCH 51/72] Update default CSR values and masks for NutShell * misa * satp * mimpid * marchid --- riscv/csrs.cc | 2 ++ riscv/encoding.h | 2 +- riscv/processor.cc | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 80847b0dae..cdf734589e 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -653,6 +653,8 @@ misa_csr_t::misa_csr_t(processor_t* const proc, const reg_t addr, const reg_t ma | (1L << ('C' - 'A')) | (1L << ('V' - 'A')) ) +#elif defined(CPU_NUTSHELL) + write_mask(0 // not allowed #else write_mask(max_isa & (0 // allow MAFDQCHV bits in MISA to be modified | (1L << ('M' - 'A')) diff --git a/riscv/encoding.h b/riscv/encoding.h index f71283ef42..57f8ab571d 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -245,7 +245,7 @@ #define SATP32_ASID 0x7FC00000 #define SATP32_PPN 0x003FFFFF #define SATP64_MODE 0xF000000000000000 -#if defined(CPU_ROCKET_CHIP) || defined(CPU_NUTSHELL) +#if defined(CPU_ROCKET_CHIP) #define SATP64_ASID 0x0000000000000000 #else #define SATP64_ASID 0x0FFFF00000000000 diff --git a/riscv/processor.cc b/riscv/processor.cc index 9041d0f94c..611ece69b1 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -448,6 +448,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) #ifdef CPU_ROCKET_CHIP csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 1); csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0x20181004); +#elif defined(CPU_NUTSHELL) + csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 0); + csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); #else csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 5); csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); From 7d4aac72d979a0f413c7bbf7988a8cbe68303bfc Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 18 Jul 2023 12:33:52 +0800 Subject: [PATCH 52/72] csrs: mstatus.fs is always zero in NutShell --- riscv/csrs.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index cdf734589e..0d3b570bad 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -521,6 +521,9 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept { if (fs == 0x1 || fs == 0x2) { new_mstatus |= 0x3 << 13; } +#elif defined(CPU_NUTSHELL) + reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); + new_mstatus ^= new_mstatus & (0x3 << 13); // FS is always zero #else const reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask); #endif From 2017630629a388195ae675ae573bd1dc739ba13b Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Jul 2023 20:23:40 +0800 Subject: [PATCH 53/72] Add support for sanitizer coverage instrumentation --- difftest/Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/difftest/Makefile b/difftest/Makefile index ba47243af6..91b1939127 100644 --- a/difftest/Makefile +++ b/difftest/Makefile @@ -24,6 +24,12 @@ SPIKE_CFLAGS += -g0 SPIKE_CXXFLAGS += -g0 endif +ifeq ($(SANCOV),1) +SPIKE_CFLAGS += -fsanitize-coverage=trace-pc-guard -fsanitize-coverage=pc-table -g +SPIKE_CXXFLAGS += -fsanitize-coverage=trace-pc-guard -fsanitize-coverage=pc-table -g +SPIKE_LDFLAGS += -fsanitize-coverage=trace-pc-guard -fsanitize-coverage=pc-table -g +endif + CONFIGURE_FLAGS = -q CC=$(CC) CXX=$(CXX) \ --with-boost=no --with-boost-asio=no --with-boost-regex=no \ CFLAGS="$(SPIKE_CFLAGS)" CXXFLAGS="$(SPIKE_CXXFLAGS)" \ @@ -48,7 +54,10 @@ $(CXX_UTILS): $(SPIKE_PATH)/spike_main/spike.cc # Dependencies for building the difftest dynamic library DIFFTEST_SOURCES = $(shell find . -maxdepth 1 -name '*.cc') $(CXX_UTILS) DIFFTEST_HEADERS = $(shell find . -maxdepth 1 -name '*.h') -CXXFLAGS = $(SPIKE_CXXFLAGS) --std=c++17 -shared -fPIC -flto +CXXFLAGS = $(SPIKE_CXXFLAGS) --std=c++17 -shared -fPIC +ifneq ($(SANCOV),1) +CXXFLAGS += -flto +endif ifneq ($(DEBUG),) CONFIGURE_FLAGS += --enable-commitlog From 3c2b4bb691bdede0cac66a2265abad624424fbc6 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Thu, 20 Jul 2023 20:23:58 +0800 Subject: [PATCH 54/72] Add the difftest_display interface --- difftest/difftest.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 8ad364c9e6..acf790a01a 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -389,6 +389,10 @@ void isa_reg_display() { ref->display(); } +void difftest_display() { + ref->display(); +} + int difftest_store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask) { return ref->store_commit(addr, data, mask); } From 437777c691fd87881408895af1174dddcbffcb47 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 21 Jul 2023 13:36:24 +0800 Subject: [PATCH 55/72] Allow the memory size to be overrided at run-time --- difftest/difftest.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index acf790a01a..784c7307a5 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -18,6 +18,7 @@ static debug_module_config_t difftest_dm_config = { extern std::vector> make_mems(const std::vector &layout); static DifftestRef *ref = nullptr; +static size_t overrided_mem_size = 0; DifftestRef::DifftestRef() : cfg(create_cfg()), @@ -252,8 +253,9 @@ void DifftestRef::display() { } const cfg_t *DifftestRef::create_cfg() { + auto mem_size = overrided_mem_size ? overrided_mem_size : CONFIG_MEMORY_SIZE; auto memory_layout = std::vector{ - mem_cfg_t{DRAM_BASE, CONFIG_MEMORY_SIZE}, + mem_cfg_t{DRAM_BASE, mem_size}, }; auto const cfg = new cfg_t( // std::pair default_initrd_bounds, @@ -415,4 +417,8 @@ void difftest_close() { delete ref; } +void difftest_set_ramsize(size_t size) { + overrided_mem_size = size; +} + } From bbd5213d70388d5070b02ae61a5f4573799b0e69 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 21 Jul 2023 13:38:48 +0800 Subject: [PATCH 56/72] Allow the mhartid to be overrided at run-time --- difftest/difftest.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 784c7307a5..6c5aa8708f 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -19,6 +19,7 @@ extern std::vector> make_mems(const std::vector &default_mem_layout, memory_layout, // const std::vector default_hartids, - std::vector{0}, + std::vector{overrided_mhartid}, // bool default_real_time_clint, false, // const reg_t default_trigger_count @@ -412,6 +413,9 @@ void difftest_load_flash(void *flash_bin, size_t size) { } +void difftest_set_mhartid(int mhartid) { + overrided_mhartid = mhartid; +} void difftest_close() { delete ref; From 7e7d660c1c341aa814fb5c0fae4d8c086cfda15a Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Fri, 21 Jul 2023 17:40:46 +0800 Subject: [PATCH 57/72] mmu: change the size of reservation sets for DIFFTEST Practical hardware designs would have reservation sets of 64B. However, Spike seems to have only byte-level reservation sets. I'm not sure whether it would violate the ISA. --- riscv/mmu.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/riscv/mmu.h b/riscv/mmu.h index 307a31cd2c..fb567272cb 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -262,8 +262,15 @@ class mmu_t } reg_t paddr = translate(generate_access_info(vaddr, STORE, {false, false, false}), 1); - if (sim->reservable(paddr)) + if (sim->reservable(paddr)) { +#ifdef DIFFTEST + // We assume practical hardware designs would have 64-byte (1 << 6 bytes) reservation sets. + auto index = [](reg_t addr) { return addr >> 6; }; + return index(load_reservation_address) == index(paddr); +#else return load_reservation_address == paddr; +#endif + } else throw trap_store_access_fault((proc) ? proc->state.v : false, vaddr, 0, 0); } From 6abfa14643a2fe742d0973c9fa9f35ea0b521275 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sat, 22 Jul 2023 22:53:47 +0800 Subject: [PATCH 58/72] sfence_vma: fix the missing flush_tlb_on_sfence_vma --- riscv/insns/sfence_vma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/insns/sfence_vma.h b/riscv/insns/sfence_vma.h index 7d6c01a8be..516ae7a7ed 100644 --- a/riscv/insns/sfence_vma.h +++ b/riscv/insns/sfence_vma.h @@ -6,4 +6,4 @@ if (STATE.v) { } else { require_privilege(get_field(STATE.mstatus->read(), MSTATUS_TVM) ? PRV_M : PRV_S); } -MMU.flush_tlb(); +MMU.flush_tlb_on_sfence_vma(); From 08ec9c423dc5fac30e0c6d957eb70265516bc563 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sat, 22 Jul 2023 22:54:18 +0800 Subject: [PATCH 59/72] difftrace: set satp_written only if vm enabled previously If virtual memory has not been enabled, the CPU is not expected to cache any PTEs and should not behave differently with Spike. --- difftest/difftrace.h | 3 ++- riscv/mmu.cc | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/difftest/difftrace.h b/difftest/difftrace.h index a93b478caa..5b55f817a2 100644 --- a/difftest/difftrace.h +++ b/difftest/difftrace.h @@ -122,6 +122,7 @@ class diff_trace_t public: bool enable_difftest_logs = false; + bool has_touched_vm = false; bool is_amo = false; bool sc_failed = false; @@ -176,7 +177,7 @@ class diff_trace_t } void on_satp_update(bool is_safe) { - if (!is_safe) { + if (!is_safe && has_touched_vm) { satp_written = true; } } diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 89be547313..740c456f35 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -510,6 +510,8 @@ reg_t mmu_t::walk(mem_access_info_t access_info) if (vm.levels == 0) return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx) & ~page_mask; // zero-extend from xlen + sim->has_touched_vm = true; + bool s_mode = mode == PRV_S; bool sum = proc->state.sstatus->readvirt(virt) & MSTATUS_SUM; bool mxr = (proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(virt)) & MSTATUS_MXR; From 31aa3bedca8d3af1576e248a8ef54d233e8f90f0 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 23 Jul 2023 10:10:56 +0800 Subject: [PATCH 60/72] decode: disable 48- and 64-bit instructions if needed There was a macro MAX_INSN_LENGTH, but it seems not to be used anywhere. We use it to decode the maximum insn_length. --- riscv/decode.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/riscv/decode.h b/riscv/decode.h index dad32a1e31..953f8f5478 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -60,12 +60,18 @@ const int NCSR = 4096; #define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT) #define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) -#define insn_length(x) \ +#define insn_length_all(x) \ (((x) & 0x03) < 0x03 ? 2 : \ ((x) & 0x1f) < 0x1f ? 4 : \ ((x) & 0x3f) < 0x3f ? 6 : \ 8) +#define insn_length(x) \ + (insn_length_all(x) > MAX_INSN_LENGTH ? MAX_INSN_LENGTH : insn_length_all(x)) +#ifdef DIFFTEST +#define MAX_INSN_LENGTH 4 +#else #define MAX_INSN_LENGTH 8 +#endif #define PC_ALIGN 2 #define Sn(n) ((n) < 2 ? X_S0 + (n) : X_Sn + (n)) From 63d1b1e0056a99cf6ef43ec1d783aac87ab35cfe Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 23 Jul 2023 13:18:42 +0800 Subject: [PATCH 61/72] Add support for the ref_skip_one interface When skipping instructions, minstret should be incremented. --- difftest/difftest.cc | 15 +++++++++++++++ difftest/difftest.h | 1 + 2 files changed, 16 insertions(+) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 6c5aa8708f..c7085da876 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -45,6 +45,17 @@ void DifftestRef::step(uint64_t n) { sim->step(n); } +void DifftestRef::skip_one(bool isRVC, bool wen, uint32_t wdest, uint64_t wdata) { + state->pc += isRVC ? 2 : 4; + // TODO: what if skip with fpwen? + if (wen) { + state->XPR.write(wdest, wdata); + } + // minstret decrements itself when written to match Spike's automated increment. + // Therefore, we need to add + 2 here. + state->minstret->write(state->minstret->read() + 2); +} + void DifftestRef::get_regs(diff_context_t *ctx) { for (int i = 0; i < NXPR; i++) { ctx->gpr[i] = state->XPR[i]; @@ -377,6 +388,10 @@ void difftest_exec(uint64_t n) { ref->step(n); } +void difftest_skip_one(bool isRVC, bool wen, uint32_t wdest, uint64_t wdata) { + ref->skip_one(isRVC, wen, wdest, wdata); +} + void difftest_init(int port) { ref = new DifftestRef; #ifdef RISCV_ENABLE_COMMITLOG diff --git a/difftest/difftest.h b/difftest/difftest.h index 03db6c1d8d..1e645f9e47 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -68,6 +68,7 @@ class DifftestRef { DifftestRef(); ~DifftestRef(); void step(uint64_t n); + void skip_one(bool isRVC, bool wen, uint32_t wdest, uint64_t wdata); void get_regs(diff_context_t *ctx); void set_regs(diff_context_t *ctx, bool on_demand); void memcpy_from_dut(reg_t dest, void* src, size_t n); From 57a8870b4dc6a68ef169b62e3e31dc21095726b6 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 4 Sep 2023 12:10:30 +0800 Subject: [PATCH 62/72] Update PMP configs for XIANGSHAN --- difftest/difftest-def.h | 4 ++++ difftest/difftest.cc | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/difftest/difftest-def.h b/difftest/difftest-def.h index 875a7f664d..dcf0045407 100644 --- a/difftest/difftest-def.h +++ b/difftest/difftest-def.h @@ -22,16 +22,20 @@ #define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x40000000UL #define CONFIG_FLASH_SIZE 0x1000UL +#define CONFIG_PMP_NUM 0 #elif defined(CPU_XIANGSHAN) #define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" #define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x10000000UL #define CONFIG_FLASH_SIZE 0x100000UL +#define CONFIG_PMP_NUM 16 +#define CONFIG_PMP_GRAN 12 #elif defined(CPU_ROCKET_CHIP) #define CONFIG_DIFF_ISA_STRING "rv64imafdczicsr_zifencei_zihpm_zicntr" #define CONFIG_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x10000000UL #define CONFIG_FLASH_SIZE 0x10000UL +#define CONFIG_PMP_NUM 0 #endif #endif diff --git a/difftest/difftest.cc b/difftest/difftest.cc index c7085da876..4ba3fc7fb6 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -28,6 +28,9 @@ DifftestRef::DifftestRef() : sim(create_sim(cfg)), p(sim->get_core(0UL)), state(p->get_state()) { +#if CONFIG_PMP_NUM > 0 + p->set_pmp_granularity(1 << CONFIG_PMP_GRAN); +#endif } DifftestRef::~DifftestRef() { @@ -285,7 +288,7 @@ const cfg_t *DifftestRef::create_cfg() { // const endianness_t default_endianness, endianness_little, // const reg_t default_pmpregions, - 0, + CONFIG_PMP_NUM, // const std::vector &default_mem_layout, memory_layout, // const std::vector default_hartids, From dc253ddb458b230a7cb855bfeea956d0f7399f6a Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 5 Sep 2023 15:13:07 +0800 Subject: [PATCH 63/72] debug,dummy: return false on out-of-range accesses --- difftest/dummy_debug.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/difftest/dummy_debug.cc b/difftest/dummy_debug.cc index 12c74c3fc4..90db8b33cd 100644 --- a/difftest/dummy_debug.cc +++ b/difftest/dummy_debug.cc @@ -10,8 +10,11 @@ dummy_debug_t::~dummy_debug_t() bool dummy_debug_t::load(reg_t addr, size_t len, uint8_t* bytes) { // addr is internal addr! - assert(addr < DM_BASE_ADDR); - assert(addr + len <= DM_END_ADDR); + // assert(addr > DM_BASE_ADDR); + // assert(addr + len <= DM_END_ADDR); + if (addr < DM_BASE_ADDR || addr + len > DM_END_ADDR) + return false; + int offset = addr / sizeof(uint8_t); memcpy(bytes, &dummy_debug_mem[offset], len); @@ -22,8 +25,10 @@ bool dummy_debug_t::store(reg_t addr, size_t len, const uint8_t* bytes) { // nothing is actually stored // because currently spike dm does not need to be working - assert(addr < DM_BASE_ADDR); - assert(addr + len <= DM_END_ADDR); + // assert(addr < DM_BASE_ADDR); + // assert(addr + len <= DM_END_ADDR); + if (addr < DM_BASE_ADDR || addr + len > DM_END_ADDR) + return false; return true; } From f857851a2f8725706ddd23bef9300c7d55b91f47 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 11 Sep 2023 16:05:37 +0800 Subject: [PATCH 64/72] Create README.md --- difftest/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 difftest/README.md diff --git a/difftest/README.md b/difftest/README.md new file mode 100644 index 0000000000..b8a9fefe59 --- /dev/null +++ b/difftest/README.md @@ -0,0 +1,31 @@ +# Spike as a Reference Model + +The Spike RISC-V ISA simulator can be a golden reference model for CPU co-simulation as well. +This directory contains the wrapper files for using Spike as the REF used in DiffTest. + +## Supported CPUs + +RISC-V allows diverse implementation-specific behaviors as long as they don't violate the ISA. +Therefore, to co-simulate Spike, one of the RISC-V implementations, with another implementation +without errors, we have to align their behaviors on the undefined or design-specific regions. + +Currently we are supporting CPUs including: +- [XiangShan](https://github.com/OpenXiangShan/XiangShan) +- - [NutShell](https://github.com/OSCPU/NutShell) +- [Rocket Chip](https://github.com/chipsalliance/rocket-chip) + +## How to Compile + +To compile the Spike into a dynamic library for co-simulation via DiffTest, run: + +``` +cd riscv-isa-sim/difftest +make CPU=XIANGSHAN -jN +``` + +Replace `XIANGSHAN` with `ROCKET` or `NUTSHELL` for co-simulation with Rocket or NutShell. + +## Coverage Instrumentation with LLVM + +Add `SANCOV=1` to the `make` command to instrument the source code with LLVM coverage. +This enables fuzzers to be guided with branch coverage feedback from a golden RISC-V model. From fe255a02791fc236b41bd0d632e739b43476803a Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Mon, 11 Sep 2023 16:08:13 +0800 Subject: [PATCH 65/72] Update README.md --- difftest/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/difftest/README.md b/difftest/README.md index b8a9fefe59..c2b67b54fb 100644 --- a/difftest/README.md +++ b/difftest/README.md @@ -11,7 +11,7 @@ without errors, we have to align their behaviors on the undefined or design-spec Currently we are supporting CPUs including: - [XiangShan](https://github.com/OpenXiangShan/XiangShan) -- - [NutShell](https://github.com/OSCPU/NutShell) +- [NutShell](https://github.com/OSCPU/NutShell) - [Rocket Chip](https://github.com/chipsalliance/rocket-chip) ## How to Compile From 549e4e9c6a9cdac83ded297cadd09ff8ada641b8 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 12 Sep 2023 10:50:50 +0800 Subject: [PATCH 66/72] proc: avoid initializing PMP entries at reset with DIFFTEST --- riscv/processor.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 611ece69b1..3a61b5fedd 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -581,12 +581,14 @@ void processor_t::reset() VU.reset(); in_wfi = false; +#ifndef DIFFTEST if (n_pmp > 0) { // For backwards compatibility with software that is unaware of PMP, // initialize PMP to permit unprivileged access to all of memory. put_csr(CSR_PMPADDR0, ~reg_t(0)); put_csr(CSR_PMPCFG0, PMP_R | PMP_W | PMP_X | PMP_NAPOT); } +#endif for (auto e : custom_extensions) // reset any extensions e.second->reset(); From c8036d771415efab262fb5b7f9d6b6324190eeda Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Tue, 12 Sep 2023 10:51:53 +0800 Subject: [PATCH 67/72] Show PMP registers on reg_display --- difftest/difftest.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 4ba3fc7fb6..29dbfb49e8 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -264,6 +264,16 @@ void DifftestRef::display() { printf("mtval: " FMT_WORD " stval: " FMT_WORD " mtvec: " FMT_WORD " stvec: " FMT_WORD "\n", state->mtval->read(), state->stval->read(), state->mtvec->read(), state->stvec->read()); printf("privilege mode:%ld\n", state->prv); + for (int i = 0; i < CONFIG_PMP_NUM; i++) { + auto cfgidx = i / 4; + if (p->get_xlen() == 64) { + cfgidx -= cfgidx % 2; + } + unsigned pmpcfg = (state->csrmap[CSR_PMPCFG0 + cfgidx]->read() >> (i % (p->get_xlen() / 8)) * 8) & 0xffU; + printf("%2d: cfg:0x%02x addr:0x%016lx", i, pmpcfg, state->pmpaddr[i]->read()); + if (i % 2 == 1) printf("\n"); + else printf(" | "); + } fflush(stdout); } From 80a3c8160f25fd53d412362edbbc2998be859b7d Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 17 Sep 2023 15:15:14 +0800 Subject: [PATCH 68/72] Update writable mask for `misa` of XiangShan --- riscv/csrs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 0d3b570bad..d205230d7c 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -656,7 +656,7 @@ misa_csr_t::misa_csr_t(processor_t* const proc, const reg_t addr, const reg_t ma | (1L << ('C' - 'A')) | (1L << ('V' - 'A')) ) -#elif defined(CPU_NUTSHELL) +#elif defined(CPU_NUTSHELL) || defined (CPU_XIANGSHAN) write_mask(0 // not allowed #else write_mask(max_isa & (0 // allow MAFDQCHV bits in MISA to be modified From 9297021aada01c72f3bf0651edfbda435d4a292f Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 17 Sep 2023 15:15:33 +0800 Subject: [PATCH 69/72] Update `mimpid` and `marchid` for XiangShan --- riscv/processor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/riscv/processor.cc b/riscv/processor.cc index 3a61b5fedd..f5ce520c33 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -451,6 +451,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) #elif defined(CPU_NUTSHELL) csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 0); csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); +#elif defined(CPU_XIANGSHAN) + csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 25); + csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); #else csrmap[CSR_MARCHID] = std::make_shared(proc, CSR_MARCHID, 5); csrmap[CSR_MIMPID] = std::make_shared(proc, CSR_MIMPID, 0); From 71de241321a8a6de5d075dc62daa0cadbf62b6ec Mon Sep 17 00:00:00 2001 From: liuweidin <47169884+liuweidin@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:14:11 +0800 Subject: [PATCH 70/72] Add support for RISC-V vector extension difftest (#3) --- difftest/difftest-def.h | 7 ++++- difftest/difftest.cc | 58 +++++++++++++++++++++++++++++++++++++++++ difftest/difftest.h | 24 +++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/difftest/difftest-def.h b/difftest/difftest-def.h index dcf0045407..0846164b59 100644 --- a/difftest/difftest-def.h +++ b/difftest/difftest-def.h @@ -15,6 +15,7 @@ #if defined(CPU_XIANGSHAN) #define CONFIG_DIFF_DEBUG_MODE +// #define CONFIG_DIFF_RVV // Default off #endif #if defined(CPU_NUTSHELL) @@ -24,7 +25,11 @@ #define CONFIG_FLASH_SIZE 0x1000UL #define CONFIG_PMP_NUM 0 #elif defined(CPU_XIANGSHAN) -#define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" + #if defined(CONFIG_DIFF_RVV) + #define CONFIG_DIFF_ISA_STRING "RV64IMAFDCV_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" + #else + #define CONFIG_DIFF_ISA_STRING "RV64IMAFDC_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_svinval" + #endif // CONFIG_DIFF_RVV #define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x10000000UL #define CONFIG_FLASH_SIZE 0x100000UL diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 29dbfb49e8..dece8108cc 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -94,6 +94,25 @@ void DifftestRef::get_regs(diff_context_t *ctx) { ctx->dscratch0 = state->csrmap[CSR_DSCRATCH0]->read(); ctx->dscratch1 = state->csrmap[CSR_DSCRATCH1]->read(); #endif // DIFF_DEBUG_MODE + +#ifdef CONFIG_DIFF_RVV + auto& vstate = p->VU; + /*******************************ONLY FOR VLEN=128,ELEN=64*******************************************/ + for(int i = 0; i < NVPR; i++){ + auto vReg_Val0 = vstate.elt(i, 0,false); + auto vReg_Val1 = vstate.elt(i, 1,false); + ctx->vr[i]._64[0] = vReg_Val0; + ctx->vr[i]._64[1] = vReg_Val1; + } + /***************************************************************************************************/ + ctx->vstart = vstate.vstart->read(); + ctx->vxsat = vstate.vxsat->read(); + ctx->vxrm = vstate.vxrm->read(); + ctx->vcsr = state->csrmap[CSR_VCSR]->read(); + ctx->vl = vstate.vl->read(); + ctx->vtype = vstate.vtype->read(); + ctx->vlenb = vstate.vlenb; +#endif // CONFIG_DIFF_RVV } void DifftestRef::set_regs(diff_context_t *ctx, bool on_demand) { @@ -183,6 +202,45 @@ void DifftestRef::set_regs(diff_context_t *ctx, bool on_demand) { state->csrmap[CSR_DSCRATCH1]->write(ctx->dscratch1); } #endif // DIFF_DEBUG_MODE + +#ifdef CONFIG_DIFF_RVV + auto& vstate = p->VU; + /**********************ONLY FOR VLEN=128,ELEN=64************************************/ + for (int i = 0; i < NVPR; i++) { + auto &vReg_Val0 = p->VU.elt(i, 0, true); + auto &vReg_Val1 = p->VU.elt(i, 1, true); + if (!on_demand || vReg_Val0 != ctx->vr[i]._64[0]) { + vReg_Val0 = ctx->vr[i]._64[0]; + } + if(!on_demand || vReg_Val1 != ctx->vr[i]._64[1]){ + vReg_Val1 = ctx->vr[i]._64[1]; + } + } + /***********************************************************************************/ + if (!on_demand || vstate.vstart->read() != ctx->vstart) { + vstate.vstart->write_raw(ctx->vstart); + } + /**********************NEED TO ADD WRITE*********************************************/ + if (!on_demand || vstate.vxsat->read() != ctx->vxsat) { + // vstate.vxsat->write(ctx->vxsat); + } + if (!on_demand || vstate.vxrm->read() != ctx->vxrm) { + vstate.vxrm->write_raw(ctx->vxrm); + } + /******************************Don't need write vcsr**********************************/ + // if (!on_demand || state->csrmap[CSR_VCSR]->read() !=ctx->vcsr) { + // csrmap[CSR_VCSR]->write(ctx->vcsr); + // } + if (!on_demand || vstate.vl->read() != ctx->vl) { + vstate.vl->write_raw(ctx->vl); + } + if (!on_demand || vstate.vtype->read() != ctx->vtype) { + vstate.vtype->write_raw(ctx->vtype); + } + if (!on_demand || vstate.vlenb != ctx->vlenb) { + vstate.vlenb = ctx->vlenb; + } +#endif // CONFIG_DIFF_RVV } void DifftestRef::memcpy_from_dut(reg_t dest, void* src, size_t n) { diff --git a/difftest/difftest.h b/difftest/difftest.h index 1e645f9e47..87baac35e3 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -19,6 +19,7 @@ enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; #define DIFFTEST_LOG_FILE nullptr #endif +/***************DON'T CHANGE ORDER****************************/ typedef struct { uint64_t gpr[32]; #ifdef CONFIG_DIFF_FPU @@ -43,6 +44,29 @@ typedef struct { uint64_t mideleg; uint64_t medeleg; uint64_t pc; +#ifdef CONFIG_DIFF_RVV + #define VLEN 128 + #define VENUM64 (VLEN/64) + #define VENUM32 (VLEN/32) + #define VENUM16 (VLEN/16) + #define VENUM8 (VLEN/8) + + union { + uint64_t _64[VENUM64]; + uint32_t _32[VENUM32]; + uint16_t _16[VENUM16]; + uint8_t _8[VENUM8]; + } vr[32]; + + uint64_t vstart; + uint64_t vxsat; + uint64_t vxrm; + uint64_t vcsr; + uint64_t vl; + uint64_t vtype; + uint64_t vlenb; +#endif // CONFIG_DIFF_RVV + #ifdef CONFIG_DIFF_DEBUG_MODE uint64_t debugMode; uint64_t dcsr; From b333b1d32f7d75ff92344ea8cf202eaa22fbcb66 Mon Sep 17 00:00:00 2001 From: weidingliu <47169884+weidingliu@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:31:30 +0800 Subject: [PATCH 71/72] difftest: fix init of mstatus (#4) --- difftest/difftest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index dece8108cc..e20405f6e7 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -131,7 +131,7 @@ void DifftestRef::set_regs(diff_context_t *ctx, bool on_demand) { if (!on_demand || state->pc != ctx->pc) { state->pc = ctx->pc; } - if (!on_demand || state->mstatus->read() != ctx->pc) { + if (!on_demand || state->mstatus->read() != ctx->mstatus) { state->mstatus->write(ctx->mstatus); } if (!on_demand || state->mcause->read() != ctx->mcause) { From 145445f218a224e2aaef763e027d94b7b49ba0e4 Mon Sep 17 00:00:00 2001 From: tastynoob <934348725@qq.com> Date: Wed, 13 Dec 2023 18:18:51 +0800 Subject: [PATCH 72/72] Update diff memcpy with COW optimization --- difftest/difftest.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/difftest/difftest.cc b/difftest/difftest.cc index e20405f6e7..8dc3dccd7e 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -245,9 +245,19 @@ void DifftestRef::set_regs(diff_context_t *ctx, bool on_demand) { void DifftestRef::memcpy_from_dut(reg_t dest, void* src, size_t n) { while (n) { - char *base = sim->addr_to_mem(dest); + bool is_zero = true; + for (int i=0; i < (PGSIZE/sizeof(uint64_t)); i++) { + if (((uint64_t*)src)[i] != 0) { + is_zero = false; + break; + } + } + size_t n_bytes = (n > PGSIZE) ? PGSIZE : n; - memcpy(base, src, n_bytes); + if (!is_zero) { + char *base = sim->addr_to_mem(dest); + memcpy(base, src, n_bytes); + } dest += PGSIZE; src = (char *)src + PGSIZE; n -= n_bytes;