From adafbd3240d0d7c32bb4b9436b5f7b3b93370b6d Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Thu, 7 Nov 2024 12:46:33 +0300 Subject: [PATCH] feat: add possibility for custom CSRs Currently in riscv-isa-sim there's no way to make a custom extension that adds new CSRs. This simple patch makes it possible via new virtual function in extension_t class. --- ci-tests/create-ci-binary-tarball | 11 +++-- ci-tests/custom-csr.cc | 81 +++++++++++++++++++++++++++++++ ci-tests/customcsr.c | 12 +++++ ci-tests/test-spike | 2 + riscv/extension.h | 1 + riscv/processor.cc | 2 + 6 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 ci-tests/custom-csr.cc create mode 100644 ci-tests/customcsr.c diff --git a/ci-tests/create-ci-binary-tarball b/ci-tests/create-ci-binary-tarball index abc9ee0188..73a549e028 100755 --- a/ci-tests/create-ci-binary-tarball +++ b/ci-tests/create-ci-binary-tarball @@ -4,7 +4,7 @@ set -e rm -rf build mkdir -p build/pk && cd "$_" -`git rev-parse --show-toplevel`/../riscv-pk/configure --host=riscv64-unknown-elf +`git rev-parse --show-toplevel`/../riscv-pk/configure --host=riscv64-unknown-elf --with-arch=rv64gc_zifencei make -j4 cd - @@ -16,9 +16,14 @@ mkdir -p build/dummy-slliuw && cd "$_" riscv64-unknown-elf-gcc -O2 -o dummy-slliuw `git rev-parse --show-toplevel`/ci-tests/dummy-slliuw.c cd - +mkdir -p build/dummycsr && cd "$_" +riscv64-unknown-elf-gcc -O2 -o customcsr `git rev-parse --show-toplevel`/ci-tests/customcsr.c +cd - + mv build/pk/pk . mv build/hello/hello . mv build/dummy-slliuw/dummy-slliuw . -tar -cf spike-ci.tar pk hello dummy-slliuw +mv build/dummycsr/customcsr . +tar -cf spike-ci.tar pk hello dummy-slliuw customcsr -rm pk hello dummy-slliuw +rm pk hello dummy-slliuw customcsr diff --git a/ci-tests/custom-csr.cc b/ci-tests/custom-csr.cc new file mode 100644 index 0000000000..a605dc31ab --- /dev/null +++ b/ci-tests/custom-csr.cc @@ -0,0 +1,81 @@ +#include +#include + + +class dummycsr_t: public csr_t { + public: + dummycsr_t(processor_t *proc, const reg_t addr): csr_t(proc, addr) {} + + reg_t read() const noexcept override { + return 42; + } + + void verify_permissions(insn_t insn, bool write) const override {} + + protected: + bool unlogged_write(const reg_t val) noexcept override { + return true; + } +}; + +// dummy extension with dummy CSRs. Nice. +struct xdummycsr_t : public extension_t { + const char *name() { return "dummycsr"; } + + xdummycsr_t() {} + + std::vector get_instructions() override { + return {}; + } + + std::vector get_disasms() override { + return {}; + } + + std::vector get_csrs(processor_t &proc) const override { + return {std::make_shared(&proc, /*Addr*/ 0xfff)}; + } +}; + +REGISTER_EXTENSION(dummycsr, []() { return new xdummycsr_t; }) + +// Copied from spike main. +// TODO: This should really be provided in libriscv +static 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; +} + +int main(int argc, char **argv) { + cfg_t cfg; + cfg.isa = "RV64IMAFDCV_Zicsr_xdummycsr"; + std::vector plugin_devices; + if (argc != 3) { + std::cerr << "Error: invalid arguments\n"; + exit(1); + } + std::vector htif_args{argv[1] /* pk */, argv[2] /* executable */}; + debug_module_config_t 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 = true}; + std::vector> mems = + make_mems(cfg.mem_layout); + sim_t sim(&cfg, false, mems, plugin_devices, htif_args, dm_config, + nullptr, // log_path + true, // dtb_enabled + nullptr, // dtb_file + false, // socket_enabled + nullptr); // cmd_file + sim.run(); +} diff --git a/ci-tests/customcsr.c b/ci-tests/customcsr.c new file mode 100644 index 0000000000..7d02689ddb --- /dev/null +++ b/ci-tests/customcsr.c @@ -0,0 +1,12 @@ +#include + +int main() { + int x = 1; + // dummycsr + asm("csrr %0, 0xfff" : "=r"(x)); + if (x == 42) + printf("Executed successfully\n"); + else + printf("FAIL. Got value: %d instead of 42\n", x); + return 0; +} diff --git a/ci-tests/test-spike b/ci-tests/test-spike index 9826232973..36b748afa1 100755 --- a/ci-tests/test-spike +++ b/ci-tests/test-spike @@ -15,9 +15,11 @@ time ../install/bin/spike --isa=rv64gc pk hello | grep "Hello, world! Pi is app # check that including sim.h in an external project works g++ -std=c++2a -I../install/include -L../install/lib $DIR/testlib.cc -lriscv -o test-libriscv g++ -std=c++2a -I../install/include -L../install/lib $DIR/test-customext.cc -lriscv -o test-customext +g++ -std=c++2a -I../install/include -L../install/lib $DIR/custom-csr.cc -lriscv -o test-custom-csr # check that all installed headers are functional g++ -std=c++2a -I../install/include -L../install/lib $DIR/testlib.cc -lriscv -o /dev/null -include ../install-hdrs-list.h LD_LIBRARY_PATH=../install/lib ./test-libriscv pk hello| grep "Hello, world! Pi is approximately 3.141588." LD_LIBRARY_PATH=../install/lib ./test-customext pk dummy-slliuw | grep "Executed successfully" +LD_LIBRARY_PATH=../install/lib ./test-custom-csr pk customcsr | grep "Executed successfully" diff --git a/riscv/extension.h b/riscv/extension.h index de6ece3e63..991da7e5b4 100644 --- a/riscv/extension.h +++ b/riscv/extension.h @@ -13,6 +13,7 @@ class extension_t public: virtual std::vector get_instructions() = 0; virtual std::vector get_disasms() = 0; + virtual std::vector get_csrs ([[maybe_unused]] processor_t &proc) const { return {}; }; virtual const char* name() = 0; virtual void reset() {}; virtual void set_debug(bool UNUSED value) {} diff --git a/riscv/processor.cc b/riscv/processor.cc index ab4ff7f7d8..ecdf392ea1 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -711,6 +711,8 @@ void processor_t::register_extension(extension_t *x) { fprintf(stderr, "extensions must have unique names (got two named \"%s\"!)\n", x->name()); abort(); } + for (auto &csr: x->get_csrs(*this)) + state.add_csr(csr->address, csr); x->set_processor(this); }