diff --git a/.envrc b/.envrc index 65d6496..6934684 100644 --- a/.envrc +++ b/.envrc @@ -6,6 +6,8 @@ if [ $distro == "CentOS" ]; then . /opt/rh/rh-python38/enable elif [ $distro == "Rocky" ]; then . /opt/rh/gcc-toolset-11/enable +elif [ $distro == "RockyLinux" ]; then + . /opt/rh/gcc-toolset-14/enable fi layout python3 [ -f .envrc.$USER ] && . .envrc.$USER diff --git a/.github/workflows/ci-compile.yml b/.github/workflows/ci-compile.yml new file mode 100644 index 0000000..03723ea --- /dev/null +++ b/.github/workflows/ci-compile.yml @@ -0,0 +1,61 @@ +name: CI C++ Std compliance + +on: + push: + paths: + - '**.hpp' + - '**.cpp' + - '**.h' + - '**.c' + - '**CMakeLists.txt' + - '.github/workflows/**' + - 'conanfile.py' + pull_request: + paths: + - '**.hpp' + - '**.cpp' + - '**.h' + - '**.c' + - '**CMakeLists.txt' + - '.github/workflows/**' + - 'conanfile.py' + +jobs: + build-and-test: + runs-on: ubuntu-latest + strategy: + matrix: + cpp_std: [17, 20] + steps: + - uses: actions/checkout@v4 + + - name: Update submodules + run: git submodule update --init --recursive + + - name: Cache Conan + uses: actions/cache@v4 + with: + path: ~/.conan2 + key: conan-${{ runner.os }}-unit-cpp${{ matrix.cpp_std }}-${{ hashFiles('conanfile.py') }} + + - name: Cache Conan + uses: actions/cache@v4 + with: + path: ~/.conan2 + key: conan-${{ runner.os }}-unit-cpp${{ matrix.cpp_std }}-${{ hashFiles('conanfile.py') }} + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y g++ python3-pip cmake + pip3 install conan + cmake --version + + - name: Configure + run: WITH_LLVM=1 cmake --preset Release -B build -DCMAKE_CXX_STANDARD=${{ matrix.cpp_std }} -DWITH_LLVM=ON + + - name: Build + run: WITH_LLVM=1 cmake --build build -j + + - name: Run smoke test + run: ./build/riscv-sim -h diff --git a/.gitignore b/.gitignore index b189e80..8120c73 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ build contrib/instr/*_fast.yaml contrib/instr/*_slow.yaml +.cache diff --git a/.vscode/settings.json b/.vscode/settings.json index fba823b..08558c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,9 +4,16 @@ "workbench.action.tasks.runTask" ], "clangd.arguments": [ - "--pretty", - "--background-index", - "--compile-commands-dir=${workspaceFolder}/build" + "--pretty", + "--background-index", + "--compile-commands-dir=${workspaceFolder}/build" ], - "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json" + "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", + "editor.rulers": [ + { + "column": 140, + "comment": "clang-format" + } + ], + "editor.formatOnSave": true } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 377c6fd..4b1d03d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) ############################################################################### # ############################################################################### -project(dbt-rise-riscv VERSION 2.0.0 LANGUAGES C CXX) +project(dbt-rise-riscv VERSION 2.1.0 LANGUAGES C CXX) option(UPDATE_EXTERNAL_PROJECT "Whether to pull changes in external projects" ON) @@ -20,7 +20,7 @@ if(NOT TARGET dbt-rise-core) dbt_rise_core_git GIT_REPOSITORY "https://github.com/Minres/DBT-RISE-Core.git" #GIT_TAG "origin/develop" - GIT_TAG 0c7532f6 + GIT_TAG cc0de2d GIT_SHALLOW OFF UPDATE_DISCONNECTED NOT ${UPDATE_EXTERNAL_PROJECT} # When enabled, this option causes the update step to be skipped. ) @@ -49,7 +49,6 @@ add_subdirectory(softvector) set(LIB_SOURCES src/iss/plugin/instruction_count.cpp src/iss/arch/rv32i.cpp - src/iss/arch/rv32imc.cpp src/iss/arch/rv32imac.cpp src/iss/arch/rv32gc.cpp src/iss/arch/rv32gcv.cpp @@ -76,12 +75,6 @@ if(TARGET yaml-cpp::yaml-cpp) ) endif() -if(WITH_TCC) - list(APPEND LIB_SOURCES - src/vm/tcc/vm_tgc5c.cpp - ) -endif() - if(WITH_LLVM) list(APPEND LIB_SOURCES src/vm/llvm/vm_tgc5c.cpp @@ -120,18 +113,13 @@ if(IS_DIRECTORY "${PROJECT_SOURCE_DIR}/../dbt-rise-custom") list(APPEND LIB_DEFINES CORE_${CORE}) endforeach() - message(STATUS "Core defines are ${LIB_DEFINES}") + #message(STATUS "Core defines are ${LIB_DEFINES}") if(WITH_LLVM) FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../dbt-rise-custom/src/vm/llvm/vm_*.cpp) list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES}) endif() - if(WITH_TCC) - FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../dbt-rise-custom/src/vm/tcc/vm_*.cpp) - list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES}) - endif() - if(WITH_ASMJIT) FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../dbt-rise-custom/src/vm/asmjit/vm_*.cpp) list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES}) @@ -139,9 +127,6 @@ if(IS_DIRECTORY "${PROJECT_SOURCE_DIR}/../dbt-rise-custom") endif() # Define the library add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES}) -if(USE_SC_SIGNAL4IRQ) - target_compile_definitions(${PROJECT_NAME} PUBLIC SC_SIGNAL_IF) -endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") @@ -238,11 +223,6 @@ if(BUILD_TESTING) add_test(NAME riscv-sim-interp COMMAND riscv-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp) - if(WITH_TCC) - add_test(NAME riscv-sim-tcc - COMMAND riscv-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc) - endif() - if(WITH_LLVM) add_test(NAME riscv-sim-llvm COMMAND riscv-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm) @@ -259,6 +239,8 @@ endif() ############################################################################### if(TARGET scc-sysc) project(dbt-rise-riscv_sc VERSION 1.0.0) + set(USE_SC_SIGNAL4IRQ OFF CACHE BOOL "Enable the use of ssc_signals for interrupt delivery") + set(LIB_SOURCES src/sysc/core_complex.cpp src/sysc/register_cores.cpp @@ -270,20 +252,44 @@ if(TARGET scc-sysc) FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../dbt-rise-custom/src/sysc/register_*.cpp) list(APPEND LIB_SOURCES ${GEN_SC_SOURCES}) endif() - add_library(${PROJECT_NAME} ${LIB_SOURCES}) - target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) - target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-riscv scc-sysc) + set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) + + add_library(${PROJECT_NAME}_sig ${LIB_SOURCES}) + target_compile_definitions(${PROJECT_NAME}_sig PUBLIC SC_SIGNAL_IF) + target_compile_definitions(${PROJECT_NAME}_sig PUBLIC WITH_SYSTEMC SC_SIGNAL_IF) + target_link_libraries(${PROJECT_NAME}_sig PUBLIC dbt-rise-riscv scc-sysc) # if(WITH_LLVM) # target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) # endif() - set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) - set_target_properties(${PROJECT_NAME} PROPERTIES + set_target_properties(${PROJECT_NAME}_sig PROPERTIES + VERSION ${PROJECT_VERSION} + FRAMEWORK FALSE + PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers + ) + install(TARGETS ${PROJECT_NAME}_sig COMPONENT ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets # for downstream dependencies + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package) + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers + ) + + add_library(${PROJECT_NAME}_tlm ${LIB_SOURCES}) + target_compile_definitions(${PROJECT_NAME}_tlm PUBLIC WITH_SYSTEMC) + target_link_libraries(${PROJECT_NAME}_tlm PUBLIC dbt-rise-riscv scc-sysc) + + # if(WITH_LLVM) + # target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) + # endif() + set_target_properties(${PROJECT_NAME}_tlm PROPERTIES VERSION ${PROJECT_VERSION} FRAMEWORK FALSE PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers ) - install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME} + install(TARGETS ${PROJECT_NAME}_tlm COMPONENT ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets # for downstream dependencies ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries @@ -292,6 +298,11 @@ if(TARGET scc-sysc) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package) INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers ) + if(USE_SC_SIGNAL4IRQ) + add_library(${PROJECT_NAME} ALIAS ${PROJECT_NAME}_sig) + else() + add_library(${PROJECT_NAME} ALIAS ${PROJECT_NAME}_tlm) + endif() endif() project(elfio-test) diff --git a/CMakePresets.json b/CMakePresets.json index 6079f1b..89795a2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -20,8 +20,8 @@ "CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "contrib/cmake/conan_provider.cmake", - "CONAN_BUILD_PROFILE": "auto-cmake", - "WITH_TCC": "OFF" + "CONAN_HOST_PROFILE": "auto-cmake", + "CONAN_BUILD_PROFILE": "conan_host_profile" } }, { diff --git a/conanfile.py b/conanfile.py index e87df7a..cb2240e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -39,12 +39,11 @@ def requirements(self): self.requires("fmt/8.0.1") self.requires("spdlog/1.9.2") self.requires("boost/1.85.0") - self.requires("abseil/20250127.0") self.requires("elfio/3.11") self.requires("lz4/1.9.3") self.requires("yaml-cpp/0.7.0") self.requires("jsoncpp/1.9.5") - self.requires("zlib/1.2.12") + self.requires("zlib/1.3.1") self.requires("asmjit/cci.20240531") if "WITH_LLVM" in os.environ: self.requires("llvm-core/19.1.7") diff --git a/contrib/fw/.gitignore b/contrib/fw/.gitignore new file mode 100644 index 0000000..105c692 --- /dev/null +++ b/contrib/fw/.gitignore @@ -0,0 +1 @@ +/bsp diff --git a/contrib/fw/hello-world/.gitignore b/contrib/fw/hello-world/.gitignore new file mode 100644 index 0000000..39c65a2 --- /dev/null +++ b/contrib/fw/hello-world/.gitignore @@ -0,0 +1,5 @@ +/*.elf +/*.dis +/*.map +/*.a +/*.o diff --git a/contrib/fw/hello-world/Makefile b/contrib/fw/hello-world/Makefile new file mode 100644 index 0000000..d8c8601 --- /dev/null +++ b/contrib/fw/hello-world/Makefile @@ -0,0 +1,19 @@ + +TARGET = hello +C_SRCS = $(wildcard *.c) +HEADERS = $(wildcard *.h) +CFLAGS += -Og -g + +BOARD=iss +LINK_TARGET=link +RISCV_ARCH:=rv32imc +RISCV_ABI:=ilp32 +#RISCV_ARCH:=rv64imc +#RISCV_ABI:=lp64 +LDFLAGS := -g -march=$(RISCV_ARCH) -mabi=$(RISCV_ABI) + +compiler := $(shell which riscv64-unknown-elf-gcc) +TOOL_DIR=$(dir $(compiler)) + +BSP_BASE ?= ../bsp +include $(BSP_BASE)/env/common-gcc.mk diff --git a/contrib/fw/hello-world/hello.c b/contrib/fw/hello-world/hello.c new file mode 100644 index 0000000..91bf133 --- /dev/null +++ b/contrib/fw/hello-world/hello.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#include +#include "encoding.h" + +int factorial(int i){ + + volatile int result = 1; + for (int ii = 1; ii <= i; ii++) { + result = result * ii; + } + return result; + +} + +int main() +{ + volatile int result = factorial (10); + printf("Factorial is %d\n", result); + printf("End of execution"); + return 0; +} diff --git a/contrib/fw/hello-world/prebuilt/hello.elf b/contrib/fw/hello-world/prebuilt/hello.elf new file mode 100755 index 0000000..95b04ad Binary files /dev/null and b/contrib/fw/hello-world/prebuilt/hello.elf differ diff --git a/gen_input/ISA b/gen_input/ISA index c0d5707..c59cf8b 160000 --- a/gen_input/ISA +++ b/gen_input/ISA @@ -1 +1 @@ -Subproject commit c0d570783c2c36080195496e6bcf5c64e9960601 +Subproject commit c59cf8b79ddba1d43720960b37db52f9cbd13c7b diff --git a/gen_input/templates/CORENAME.h.gtl b/gen_input/templates/CORENAME.h.gtl index f9e729f..d59ebc6 100644 --- a/gen_input/templates/CORENAME.h.gtl +++ b/gen_input/templates/CORENAME.h.gtl @@ -46,6 +46,15 @@ def nativeSize(int size){ def getCString(def val){ return val.toString()+'ULL' } +def overflowsafeSize(BigInteger val){ + switch(val) { + //case 256: return "std::numeric_limits::max()"; + //case 65536: return "std::numeric_limits::max()"; + //case 4294967296: return "std::numeric_limits::max()"; + case 18446744073709551616: return "std::numeric_limits::max()"; + default: return val; + } +} %> #ifndef _${coreDef.name.toUpperCase()}_H_ #define _${coreDef.name.toUpperCase()}_H_ @@ -200,8 +209,14 @@ template <> struct traits<${coreDef.name.toLowerCase()}> { enum sreg_flag_e { FLAGS }; - enum mem_type_e { ${spaces.collect{it.name}.join(', ')}, IMEM = MEM }; + enum mem_type_e { ${spaces.collect{it.name}.join(', ')}, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + ${spaces.collect{overflowsafeSize(it.value)}.join(',\n ')} + }}; + + static constexpr uint64_t max_mem_size = ${overflowsafeSize(spaces.collect{it.value}.max())}; + enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %> ${instr.instruction.name} = ${index},<%}%> MAX_OPCODE diff --git a/gen_input/templates/asmjit/CORENAME.cpp.gtl b/gen_input/templates/asmjit/CORENAME.cpp.gtl index 25af08d..76b4845 100644 --- a/gen_input/templates/asmjit/CORENAME.cpp.gtl +++ b/gen_input/templates/asmjit/CORENAME.cpp.gtl @@ -365,9 +365,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index 0d088c3..ed8c026 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -295,7 +295,7 @@ private: decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -399,6 +399,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case")<%}%> default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/gen_input/templates/llvm/CORENAME.cpp.gtl b/gen_input/templates/llvm/CORENAME.cpp.gtl index 3b63455..36d5bb9 100644 --- a/gen_input/templates/llvm/CORENAME.cpp.gtl +++ b/gen_input/templates/llvm/CORENAME.cpp.gtl @@ -271,11 +271,9 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, BasicBlock *this_block) // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; code_word_t instr = 0; - // const typename traits::addr_t upper_bits = ~traits::PGMASK; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); - if (res != iss::Ok) + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); + if (res != iss::Ok) return std::make_tuple(ILLEGAL_FETCH, nullptr); if (instr == 0x0000006f || (instr&0xffff)==0xa001){ this->builder.CreateBr(this->leave_blk); diff --git a/src/iss/arch/mstatus.h b/src/iss/arch/mstatus.h index 1795f0c..2ea36d3 100644 --- a/src/iss/arch/mstatus.h +++ b/src/iss/arch/mstatus.h @@ -73,6 +73,8 @@ template struct status(v); }; // machine previous privilege static inline unsigned MPP(T v) { return bit_sub<11, 2>(v); }; + // vector unit status Off/Initial/Clean/Dirty + static inline unsigned VS(T v) { return bit_sub<9, 2>(v); }; // supervisor previous privilege static inline unsigned SPP(T v) { return bit_sub<8, 1>(v); }; // previous machine interrupt-enable @@ -121,6 +123,8 @@ template struct status(v); }; // machine previous privilege static inline unsigned MPP(T v) { return bit_sub<11, 2>(v); }; + // vector unit status Off/Initial/Clean/Dirty + static inline unsigned VS(T v) { return bit_sub<9, 2>(v); }; // supervisor previous privilege static inline unsigned SPP(T v) { return bit_sub<8, 1>(v); }; // previous machine interrupt-enable @@ -165,6 +169,8 @@ template class hart_state class hart_state #include #include @@ -52,6 +51,9 @@ #include #include #include +#include +#include +#include #include #include @@ -305,7 +307,79 @@ template struct priv_if { unsigned& max_irq; }; -template struct riscv_hart_common : public BASE, public mem::memory_elem { +template struct riscv_hart_common : public BASE, public mem::memory_elem { + + constexpr static unsigned MEM = traits::MEM; + + using core = BASE; + using this_class = riscv_hart_common; + using reg_t = typename core::reg_t; + + using rd_csr_f = std::function; + using wr_csr_f = std::function; + + // Extension status bits (SD needs to be set when any of FS / VS / XS are dirty [0b11]): + // TODO implement XS + static constexpr uint32_t extension_status_mask = + (traits::FP_REGS_SIZE ? (0b11u << 13) : 0u) | (traits::V_REGS_SIZE ? (0b11u << 9) : 0u); + + // Notation for differing fields is: 32 bits / 64 bits + static constexpr uint32_t mstatus_lower = 0b00000000000000000001100010001000; + static constexpr uint32_t sstatus_lower = 0b00000000011111100000000100100010; + static constexpr uint32_t ustatus_lower = 0b00000000000000000000000000010001; + // ||||||/|||||||||/|/|/|/||||||||| + // |||||/ ||||||||| | | | ||||||||+-- UIE + // ||||/||||||||||| | | | |||||||+--- SIE + // |||/|||||||||||| | | | ||||||+---- WPRI + // ||/||||||||||||| | | | |||||+----- MIE + // |||||||||||||||| | | | ||||+------ UPIE + // |||||||||||||||| | | | |||+------- SPIE + // |||||||||||||||| | | | ||+-------- UBE + // |||||||||||||||| | | | |+--------- MPIE + // |||||||||||||||| | | | +---------- SPP + // |||||||||||||||| | | +------------ VS + // |||||||||||||||| | +-------------- MPP + // |||||||||||||||| +---------------- FS + // |||||||||||||||+------------------ XS + // ||||||||||||||+------------------- MPRV + // |||||||||||||+-------------------- SUM + // ||||||||||||+--------------------- MXR + // |||||||||||+---------------------- TVM + // ||||||||||+----------------------- TW + // |||||||||+------------------------ TSR + // ||||||||+------------------------- SPELP + // |||||||+-------------------------- SDT + // |++++++--------------------------- WPRI + // +--------------------------------- SD / WPRI + + // upper half does not correspond to mstatush bit meanings (UXL and SXL) + static constexpr uint32_t mstatus_upper = 0b00000000000000000000000000001111; + static constexpr uint32_t sstatus_upper = 0b00000000000000000000000000000011; + // |||||||||||||||||||||||||||||/|/ + // ||||||||||||||||||||||||||||| +--- WPRI / UXL + // ||||||||||||||||||||||||||||+----- WPRI / SXL + // |||||||||||||||||||||||||||+------ SBE + // |||||||||||||||||||||||||+-------- MBE + // ||||||||||||||||||||||||+--------- GVA + // |||||||||||||||||||||||+---------- MPV + // ||||||||||||||||||||||+----------- WPRI + // |||||||||||||||||||||+------------ MPELP + // ||||||||||||||||||||+------------- MDT + // |+++++++++++++++++++-------------- WPRI + // +--------------------------------- WPRI / SD + + static constexpr reg_t get_mstatus_mask() { + if constexpr(sizeof(reg_t) == 4) + return mstatus_lower | riscv_hart_common::extension_status_mask; + else if constexpr(sizeof(reg_t) == 8) + return static_cast(mstatus_upper) << 32 | mstatus_lower | riscv_hart_common::extension_status_mask; + else + static_assert("Unsupported XLEN value"); + } + static constexpr reg_t get_mu_status_mask(unsigned priv_lvl) { return ustatus_lower | (priv_lvl >= PRIV_M ? get_mstatus_mask() : 0); } + static constexpr reg_t get_msu_status_mask(unsigned priv_lvl) { + return get_mu_status_mask(priv_lvl) | ((priv_lvl >= PRIV_S) ? sstatus_lower : 0); + } const std::array lvl = {{'U', 'S', 'H', 'M'}}; const std::array trap_str = {{"" "Instruction address misaligned", // 0 @@ -328,14 +402,6 @@ template struct riscv_hart_co "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; - constexpr static unsigned MEM = traits::MEM; - - using core = BASE; - using this_class = riscv_hart_common; - using reg_t = typename core::reg_t; - - using rd_csr_f = std::function; - using wr_csr_f = std::function; #define MK_CSR_RD_CB(FCT) [this](unsigned a, reg_t& r) -> iss::status { return this->FCT(a, r); }; #define MK_CSR_WR_CB(FCT) [this](unsigned a, reg_t r) -> iss::status { return this->FCT(a, r); }; @@ -434,7 +500,7 @@ template struct riscv_hart_co ~riscv_hart_common() { if(io_buf.str().length()) { - CPPLOG(INFO) << "tohost send '" << io_buf.str() << "'"; + ILOG(isslogger, logging::INFO, fmt::format("tohost send '{}'", io_buf.str())); } } @@ -446,22 +512,22 @@ template struct riscv_hart_co void set_semihosting_callback(semihosting_cb_t cb) { semihosting_cb = cb; }; - std::pair load_file(std::string name, int type) { + std::pair load_file(std::string const& name, int type) override { return std::make_pair(entry_address, read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64)); } - bool read_elf_file(std::string name, uint8_t expected_elf_class) { + bool read_elf_file(std::string const& name, uint8_t expected_elf_class) { // Create elfio reader ELFIO::elfio reader; // Load ELF data if(reader.load(name)) { // check elf properties if(reader.get_class() != expected_elf_class) { - CPPLOG(ERR) << "ISA missmatch, selected XLEN does not match supplied file "; + ILOG(isslogger, logging::ERR, "ISA missmatch, selected XLEN does not match supplied file "); return false; } if(reader.get_type() != ELFIO::ET_EXEC && reader.get_type() != ELFIO::ET_DYN) { - CPPLOG(ERR) << "Input is neither an executable nor a pie executable (dyn)"; + ILOG(isslogger, logging::ERR, "Input is neither an executable nor a pie executable (dyn)"); return false; } if(reader.get_machine() != ELFIO::EM_RISCV) @@ -472,10 +538,12 @@ template struct riscv_hart_co const auto seg_data = pseg->get_data(); const auto type = pseg->get_type(); if(type == ELFIO::PT_LOAD && fsize > 0) { - auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits::MEM, - pseg->get_physical_address(), fsize, reinterpret_cast(seg_data)); + auto res = this->write( + {iss::address_type::LOGICAL, iss::access_type::DEBUG_WRITE, traits::IMEM, pseg->get_physical_address()}, + fsize, reinterpret_cast(seg_data)); if(res != iss::Ok) - CPPLOG(ERR) << "problem writing " << fsize << " bytes to 0x" << std::hex << pseg->get_physical_address(); + ILOG(isslogger, logging::ERR, + fmt::format("problem writing {} bytes to 0x{:x}", fsize, pseg->get_physical_address())); } } const auto sym_sec = reader.sections[".symtab"]; @@ -494,7 +562,7 @@ template struct riscv_hart_co if(name != "") { this->symbol_table[name] = value; #ifndef NDEBUG - CPPLOG(TRACE) << "Found Symbol " << name; + ILOG(isslogger, logging::TRACE, fmt::format("Found Symbol {}", name)); #endif } } @@ -515,14 +583,14 @@ template struct riscv_hart_co uint64_t buf_ptr = loaded_payload[2]; uint64_t len = loaded_payload[3]; std::vector buf(len); - if(aif->read(address_type::PHYSICAL, access_type::DEBUG_READ, mem_type, buf_ptr, len, reinterpret_cast(buf.data()))) { - CPPLOG(ERR) << "SYS_WRITE buffer read went wrong"; + if(aif->read({address_type::LOGICAL, access_type::DEBUG_READ, mem_type, buf_ptr}, len, reinterpret_cast(buf.data()))) { + ILOG(isslogger, logging::ERR, "SYS_WRITE buffer read went wrong"); return iss::Err; } // we disregard the fd and just log to stdout for(size_t i = 0; i < len; i++) { if(buf[i] == '\n' || buf[i] == '\0') { - CPPLOG(INFO) << "tohost send '" << io_buf.str() << "'"; + ILOG(isslogger, logging::INFO, fmt::format("tohost send '{}'", io_buf.str())); io_buf.str(""); } else io_buf << buf[i]; @@ -531,8 +599,8 @@ template struct riscv_hart_co // Not sure what the correct return value should be uint8_t ret_val = 1; if(fromhost != std::numeric_limits::max()) - if(aif->write(address_type::PHYSICAL, access_type::DEBUG_WRITE, mem_type, fromhost, 1, &ret_val)) { - CPPLOG(ERR) << "Fromhost write went wrong"; + if(aif->write({address_type::LOGICAL, access_type::DEBUG_WRITE, mem_type, fromhost}, 1, &ret_val) != iss::Ok) { + ILOG(isslogger, logging::ERR, "Fromhost write went wrong"); return iss::Err; } return iss::Ok; @@ -542,12 +610,13 @@ template struct riscv_hart_co constexpr reg_t get_pc_mask() { return has_compressed() ? (reg_t)~1 : (reg_t)~3; } - void disass_output(uint64_t pc, const std::string instr) override { - // NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], - // (reg_t)state.mstatus, - // this->reg.cycle + cycle_offset); - NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};c:{}]", pc, instr, lvl[this->reg.PRIV], - this->reg.cycle + cycle_offset); + void disass_output(uint64_t pc, std::string const& instr) override { + static CONSTEXPR char const* fmt_str = + sizeof(reg_t) == 4 ? "0x{:08x} {:40} [p:{};s:0x{:02x};i:{};c:{}]" : "0x{:012x} {:40} [p:{};s:0x{:04x};i:{};c:{}]"; + if(::logging::DEBUG <= disasslogger.get_log_level()) + ILOG(disasslogger, ::logging::DEBUG, + fmt::format(fmt_str, pc, instr, lvl[this->reg.PRIV], (reg_t)this->state.mstatus, this->reg.icount, + this->reg.cycle + cycle_offset)); }; void register_csr(unsigned addr, rd_csr_f f) { csr_rd_cb[addr] = f; } @@ -854,63 +923,71 @@ template struct riscv_hart_co } iss::status read_vlenb(unsigned addr, reg_t& val) { - val = csr[vlenb]; + val = traits::V_REGS_SIZE; return iss::Ok; } priv_if get_priv_if() { - return priv_if{.read_csr = [this](unsigned addr, reg_t& val) -> iss::status { return read_csr(addr, val); }, - .write_csr = [this](unsigned addr, reg_t val) -> iss::status { return write_csr(addr, val); }, - .exec_htif = [this](uint8_t const* data, unsigned length) -> iss::status { return execute_htif(data, length); }, - .raise_trap = - [this](uint16_t trap_id, uint16_t cause, reg_t fault_data) { - this->reg.trap_state = 0x80ULL << 24 | (cause << 16) | trap_id; - this->fault_data = fault_data; - }, - .csr_rd_cb{this->csr_rd_cb}, - .csr_wr_cb{csr_wr_cb}, - .state{this->state}, - .PRIV{this->reg.PRIV}, - .PC{this->reg.PC}, - .tohost{this->tohost}, - .fromhost{this->fromhost}, - .max_irq{mcause_max_irq}}; + return priv_if{ + .read_csr = [this](unsigned addr, reg_t& val) -> iss::status { return read_csr(addr, val); }, + .write_csr = [this](unsigned addr, reg_t val) -> iss::status { return write_csr(addr, val); }, + .exec_htif = [this](uint8_t const* data, unsigned length) -> iss::status { return execute_htif(data, length); }, + .raise_trap = + [this](uint16_t trap_id, uint16_t cause, reg_t fault_data) { + this->reg.trap_state = 0x80ULL << 24 | (cause << 16) | trap_id; + this->fault_data = fault_data; + }, + .csr_rd_cb{this->csr_rd_cb}, + .csr_wr_cb{csr_wr_cb}, + .state{this->state}, + .PRIV{this->reg.PRIV}, + .PC{this->reg.PC}, + .tohost{this->tohost}, + .fromhost{this->fromhost}, + .max_irq{mcause_max_irq}}; } iss::status execute_htif(uint8_t const* data, unsigned length) { reg_t cur_data{0}; memcpy(&cur_data, data, length); + // according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754: // Extract Device (bits 63:56) uint8_t device = traits::XLEN == 32 ? 0 : (cur_data >> 56) & 0xFF; // Extract Command (bits 55:48) uint8_t command = traits::XLEN == 32 ? 0 : (cur_data >> 48) & 0xFF; // Extract payload (bits 47:0) - uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL; - if(payload_addr & 1) { - CPPLOG(FATAL) << "this->tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr - << "), stopping simulation"; + uint64_t payload_data = cur_data & 0xFFFFFFFFFFFFULL; + if(payload_data & 1) { + if(payload_data & ~1) { + ILOG(isslogger, logging::FATAL, + fmt::format("this->tohost value is 0x{:x} ({}), stopping simulation", payload_data, payload_data)); + } else { + ILOG(isslogger, logging::INFO, + fmt::format("this->tohost value is 0x{:x} ({}), stopping simulation", payload_data, payload_data)); + } this->reg.trap_state = std::numeric_limits::max(); - this->interrupt_sim = payload_addr; + this->interrupt_sim = payload_data; return iss::Ok; } else if(device == 0 && command == 0) { std::array loaded_payload; - if(memory.rd_mem(access_type::DEBUG_READ, payload_addr, 8 * sizeof(uint64_t), + if(memory.rd_mem({address_type::LOGICAL, access_type::DEBUG_READ, traits::MEM, payload_data}, 8 * sizeof(uint64_t), reinterpret_cast(loaded_payload.data())) == iss::Err) - CPPLOG(ERR) << "Syscall read went wrong"; + ILOG(isslogger, logging::ERR, "Syscall read went wrong"); uint64_t syscall_num = loaded_payload.at(0); if(syscall_num == 64) { // SYS_WRITE return this->execute_sys_write(this, loaded_payload, traits::MEM); } else { - CPPLOG(ERR) << "this->tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num - << ") not implemented"; + ILOG(isslogger, logging::ERR, + fmt::format("this->tohost syscall with number 0x{:x} ({}) not implemented", syscall_num, syscall_num)); this->reg.trap_state = std::numeric_limits::max(); - this->interrupt_sim = payload_addr; + this->interrupt_sim = payload_data; return iss::Ok; } } else { - CPPLOG(ERR) << "this->tohost functionality not implemented for device " << device << " and command " << command; + ILOG(isslogger, logging::ERR, + fmt::format("this->tohost functionality not implemented for device {} and command {}", device, command)); this->reg.trap_state = std::numeric_limits::max(); - this->interrupt_sim = payload_addr; + this->interrupt_sim = payload_data; return iss::Ok; } } @@ -927,12 +1004,14 @@ template struct riscv_hart_co void set_irq_num(unsigned i) { mcause_max_irq = std::max(1u << util::ilog2(i), 16u); } protected: + util::InstanceLogger disasslogger; + util::InstanceLogger isslogger; hart_state state; mem::memory_if memory; struct riscv_instrumentation_if : public iss::instrumentation_if { - riscv_instrumentation_if(riscv_hart_common& arch) + riscv_instrumentation_if(riscv_hart_common& arch) : arch(arch) {} /** * get the name of this architecture @@ -963,7 +1042,7 @@ template struct riscv_hart_co std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } - riscv_hart_common& arch; + riscv_hart_common& arch; }; friend struct riscv_instrumentation_if; diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index ef7f96a..7e40196 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -38,7 +38,6 @@ #include "iss/arch/traits.h" #include "iss/vm_if.h" #include "iss/vm_types.h" -#include "riscv_hart_common.h" #include "util/logging.h" #include #include @@ -55,55 +54,20 @@ namespace iss { namespace arch { -template -class riscv_hart_m_p : public riscv_hart_common { +template class riscv_hart_m_p : public riscv_hart_common { public: using core = BASE; using base = riscv_hart_common; - using this_class = riscv_hart_m_p; + using this_class = riscv_hart_m_p; using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - static constexpr reg_t get_mstatus_mask() { - if(sizeof(reg_t) == 4) - // return 0x807ff988UL; // 0b1000 0000 0111 1111 1111 1000 1000 1000 // only machine mode is supported - // +-SD - // | +-TSR - // | |+-TW - // | ||+-TVM - // | |||+-MXR - // | ||||+-SUM - // | |||||+-MPRV - // | |||||| +-XS - // | |||||| | +-FS - // | |||||| | | +-MPP - // | |||||| | | | +-SPP - // | |||||| | | | |+-MPIE - // | ||||||/|/|/| || +-MIE - return 0b00000000000000000001100010001000; - else if(sizeof(reg_t) == 8) - // return 0x8000000f007ff9ddULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011 - // - // +-TSR - // |+-TW - // ||+-TVM - // |||+-MXR - // ||||+-SUM - // |||||+-MPRV - // |||||| +-XS - // |||||| | +-FS - // |||||| | | +-MPP - // |||||| | | | +-SPP - // |||||| | | | |+-MPIE - // ||||||/|/|/| || +-MIE - return 0b00000000000000000001100010001000; - else - assert(false && "Unsupported XLEN value"); - } - void write_mstatus(reg_t val) { - auto mask = get_mstatus_mask() & 0xff; // MPP is hardcoded as 0x3 + constexpr auto mask = base::get_mstatus_mask(); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -113,10 +77,8 @@ class riscv_hart_m_p : public riscv_hart_common { void reset(uint64_t address) override; - iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - uint8_t* const data); - iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - const uint8_t* const data); + iss::status read(const addr_t& addr, const unsigned length, uint8_t* const data); + iss::status write(const addr_t& addr, const unsigned length, const uint8_t* const data); uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; @@ -125,11 +87,6 @@ class riscv_hart_m_p : public riscv_hart_common { void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } protected: - using mem_read_f = iss::status(iss::phys_addr_t addr, unsigned, uint8_t* const); - using mem_write_f = iss::status(iss::phys_addr_t addr, unsigned, uint8_t const* const); - - hart_state state; - std::unordered_map atomic_reservation; iss::status read_status(unsigned addr, reg_t& val); @@ -139,11 +96,11 @@ class riscv_hart_m_p : public riscv_hart_common { iss::status read_ip(unsigned addr, reg_t& val); void check_interrupt(); - mem::memory_with_htif default_mem; + mem::neumann_memory_with_htif default_mem; }; -template -riscv_hart_m_p::riscv_hart_m_p() +template +riscv_hart_m_p::riscv_hart_m_p() : default_mem(base::get_priv_if()) { this->csr_rd_cb[mstatus] = MK_CSR_RD_CB(read_status); this->csr_wr_cb[mstatus] = MK_CSR_WR_CB(write_status); @@ -161,49 +118,24 @@ riscv_hart_m_p::riscv_hart_m_p() this->memories.append(default_mem); } -template -iss::status riscv_hart_m_p::read(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, uint8_t* const data) { +template +iss::status riscv_hart_m_p::read(const addr_t& a, const unsigned length, uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; + #ifndef NDEBUG - if(access && iss::access_type::DEBUG) { - CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; + if(is_debug(access)) { + ILOG(isslogger, logging::TRACEALL, fmt::format("debug read of {} bytes @addr 0x{:x}", length, addr)); } else if(is_fetch(access)) { - CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("fetch of {} bytes @addr 0x{:x}", length, addr)); } else { - CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("read of {} bytes @addr 0x{:x}", length, addr)); } #endif try { switch(space) { - case traits::MEM: { - auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); - if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - this->fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31); // issue trap 0 - return iss::Err; - } - try { - if(!is_debug(access) && (addr & (alignment - 1))) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; - this->fault_data = addr; - return iss::Err; - } - auto res = this->memory.rd_mem(access, addr, length, data); - if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_LOAD_ACCESS << 16; - this->fault_data = addr; - } - return res; - } catch(trap_access& ta) { - if((access & access_type::DEBUG) == 0) { - this->reg.trap_state = (1UL << 31) | ta.id; - this->fault_data = ta.addr; - } - return iss::Err; - } - } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; @@ -232,8 +164,35 @@ iss::status riscv_hart_m_p::read(const address_type type, co } else memset(data, 0, length); } break; - default: - return iss::Err; // assert("Not supported"); + default: { + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { + this->fault_data = addr; + if(is_debug(access)) + throw trap_access(0, addr); + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; + return iss::Err; + } + try { + if(!is_debug(access) && (addr & (alignment - 1))) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; + this->fault_data = addr; + return iss::Err; + } + auto res = this->memory.rd_mem({address_type::PHYSICAL, a.access, a.space, a.val}, length, data); + if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_LOAD_ACCESS << 16; + this->fault_data = addr; + } + return res; + } catch(trap_access& ta) { + if((access & access_type::DEBUG) == 0) { + this->reg.trap_state = (1UL << 31) | ta.id; + this->fault_data = ta.addr; + } + return iss::Err; + } + } break; } return iss::Ok; } catch(trap_access& ta) { @@ -245,61 +204,37 @@ iss::status riscv_hart_m_p::read(const address_type type, co } } -template -iss::status riscv_hart_m_p::write(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, const uint8_t* const data) { +template +iss::status riscv_hart_m_p::write(const addr_t& a, const unsigned length, const uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; #ifndef NDEBUG - const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; + const char* prefix = (is_debug(access)) ? "debug " : ""; switch(length) { case 8: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 4: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 2: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 1: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, (uint16_t)data[0], addr)); break; default: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("{}write of {} bytes @addr 0x{:x}", prefix, length, addr)); } #endif try { switch(space) { - case traits::MEM: { - if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { - this->fault_data = addr; - if(access && iss::access_type::DEBUG) - throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31); // issue trap 0 - return iss::Err; - } - try { - auto alignment = std::min(length, sizeof(reg_t)); - if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_STORE << 16; - this->fault_data = addr; - return iss::Err; - } - auto res = this->memory.wr_mem(access, addr, length, data); - if(unlikely(res != iss::Ok && !is_debug(access))) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_STORE_ACCESS << 16; - this->fault_data = addr; - } - return res; - } catch(trap_access& ta) { - this->reg.trap_state = (1UL << 31) | ta.id; - this->fault_data = ta.addr; - return iss::Err; - } - } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; @@ -323,8 +258,33 @@ iss::status riscv_hart_m_p::write(const address_type type, c case traits::RES: { atomic_reservation[addr] = data[0]; } break; - default: - return iss::Err; + default: { + if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { + this->fault_data = addr; + if(access && access_type::DEBUG) + throw trap_access(0, addr); + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; + return iss::Err; + } + try { + auto alignment = std::min(length, sizeof(reg_t)); + if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_STORE << 16; + this->fault_data = addr; + return iss::Err; + } + auto res = this->memory.wr_mem({address_type::PHYSICAL, a.access, a.space, a.val}, length, data); + if(unlikely(res != iss::Ok && !is_debug(access))) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_STORE_ACCESS << 16; + this->fault_data = addr; + } + return res; + } catch(trap_access& ta) { + this->reg.trap_state = (1UL << 31) | ta.id; + this->fault_data = ta.addr; + return iss::Err; + } + } break; } return iss::Ok; } catch(trap_access& ta) { @@ -336,54 +296,49 @@ iss::status riscv_hart_m_p::write(const address_type type, c } } -template -iss::status riscv_hart_m_p::read_status(unsigned addr, reg_t& val) { - val = this->state.mstatus & get_mstatus_mask(); +template iss::status riscv_hart_m_p::read_status(unsigned addr, reg_t& val) { + val = this->state.mstatus & base::get_mstatus_mask(); return iss::Ok; } -template -iss::status riscv_hart_m_p::write_status(unsigned addr, reg_t val) { +template iss::status riscv_hart_m_p::write_status(unsigned addr, reg_t val) { write_mstatus(val); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t& val) { +template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t& val) { auto mask = riscv_hart_common::get_irq_mask(3); val = this->csr[mie] & mask; return iss::Ok; } -template -iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t val) { +template iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t val) { auto mask = riscv_hart_common::get_irq_mask(3); this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t& val) { +template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t& val) { auto mask = riscv_hart_common::get_irq_mask(3); val = this->csr[mip] & mask; return iss::Ok; } -template inline void riscv_hart_m_p::reset(uint64_t address) { +template inline void riscv_hart_m_p::reset(uint64_t address) { BASE::reset(address); this->state.mstatus = hart_state::mstatus_reset_val; } -template void riscv_hart_m_p::check_interrupt() { +template void riscv_hart_m_p::check_interrupt() { // Multiple simultaneous interrupts and traps at the same privilege level are // handled in the following decreasing priority order: // external interrupts, software interrupts, timer interrupts, then finally // any synchronous traps. auto ena_irq = this->csr[mip] & this->csr[mie]; - bool mstatus_mie = state.mstatus.MIE; + bool mstatus_mie = this->state.mstatus.MIE; auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie; auto enabled_interrupts = m_enabled ? ena_irq : 0; @@ -397,8 +352,7 @@ template void riscv_hart_m_p -uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) { +template uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) { // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // calculate and write mcause val auto const trap_id = bit_sub<0, 16>(flags); @@ -438,9 +392,9 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t // Check for semihosting call std::array data; // check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07 - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data()); + this->memory.rd_mem({address_type::PHYSICAL, access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, data.data()); addr += 8; - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data() + 4); + this->memory.rd_mem({address_type::PHYSICAL, access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, data.data() + 4); const std::array ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40}; if(data == ref_data) { @@ -452,8 +406,7 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t #else sprintf(buffer.data(), "0x%016lx", addr); #endif - NSCLOG(INFO, LOGCAT) << "Semihosting call at address " << buffer.data() << " occurred "; - + ILOG(disasslogger, logging::INFO, fmt::format("Semihosting call at address {} occurred ", buffer.data())); this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } @@ -491,8 +444,8 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t // calculate adds// set NEXT_PC to trap addressess to jump to based on MODE if(trap_id != 0 && (xtvec & 0x3UL) == 3UL) { reg_t data; - auto ret = - this->memory.rd_mem(iss::access_type::DEBUG_READ, this->csr[arch::mtvt], sizeof(reg_t), reinterpret_cast(&data)); + auto ret = this->memory.rd_mem({address_type::PHYSICAL, access_type::DEBUG_READ, traits::MEM, this->csr[arch::mtvt]}, + sizeof(reg_t), reinterpret_cast(&data)); if(ret == iss::Err) return this->reg.PC; this->reg.NEXT_PC = data; @@ -508,22 +461,27 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t #else sprintf(buffer.data(), "0x%016lx", addr); #endif - if((flags & 0xffffffff) != 0xffffffff) - NSCLOG(DEBUG, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" - << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" << " at address " - << buffer.data() << " occurred"; + if((flags & 0xffffffff) != 0xffffffff) { + if(trap_id) { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", this->irq_str[cause], cause, buffer.data())); + } else { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Trap with cause '{}' ({}) occurred at address {}", this->trap_str[cause], cause, buffer.data())); + } + } // reset trap state this->reg.PRIV = new_priv; this->reg.trap_state = 0; return this->reg.NEXT_PC; } -template uint64_t riscv_hart_m_p::leave_trap(uint64_t flags) { +template uint64_t riscv_hart_m_p::leave_trap(uint64_t flags) { this->state.mstatus.MIE = this->state.mstatus.MPIE; this->state.mstatus.MPIE = 1; // sets the pc to the value stored in the x epc register. this->reg.NEXT_PC = this->csr[mepc] & this->get_pc_mask(); - NSCLOG(INFO, LOGCAT) << "Executing xRET"; + ILOG(disasslogger, logging::DEBUG, "Executing xRET"); check_interrupt(); this->reg.trap_state = this->reg.pending_trap; return this->reg.NEXT_PC; diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index f398e75..89ca0f4 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -59,8 +59,7 @@ namespace iss { namespace arch { -template -class riscv_hart_msu_vp : public riscv_hart_common { +template class riscv_hart_msu_vp : public riscv_hart_common { public: using core = BASE; using base = riscv_hart_common; @@ -68,68 +67,20 @@ class riscv_hart_msu_vp : public riscv_hart_common { using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; -#else - switch(priv_lvl) { - case PRIV_U: - return 0x80000000UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 - case PRIV_S: - return 0x800de762UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011 - default: - return 0x801fffeaUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 - } -#endif - } else if(sizeof(reg_t) == 8) { - switch(priv_lvl) { - case PRIV_U: - return 0x8000000f00000000ULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011 - case PRIV_S: - return 0x80000003000de762ULL; // 0b1...0 0011 0000 0000 0000 1101 1110 0111 0110 0010 - default: - return 0x80000030001fffeaULL; // 0b1...0 0000 0000 0000 0001 1111 1111 1111 1110 1010 - } - } else - assert(false && "Unsupported XLEN value"); - } - static constexpr reg_t get_mstatus_rd_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { - return get_mstatus_mask(priv_lvl); - } else if(sizeof(reg_t) == 8) { - auto wr_mask = get_mstatus_mask(priv_lvl); - switch(priv_lvl) { - case PRIV_U: - return wr_mask; - case PRIV_S: - return wr_mask |= 0x300000000; - default: - return wr_mask |= 0xf00000000; - } - } else - assert(false && "Unsupported XLEN value"); - } - - template ::value>* = nullptr> - void write_mstatus(T_ val, unsigned priv_lvl) { - reg_t old_val = this->state.mstatus; - auto mask = get_mstatus_mask(priv_lvl); - auto new_val = (old_val & ~mask) | (val & mask); - this->state.mstatus = new_val; - } - - template ::value>* = nullptr> - void write_mstatus(T_ val, unsigned priv_lvl) { + void write_mstatus(reg_t val, unsigned priv_lvl) { reg_t old_val = this->state.mstatus; - auto mask = get_mstatus_mask(priv_lvl); + auto mask = base::get_msu_status_mask(priv_lvl); auto new_val = (old_val & ~mask) | (val & mask); - if((new_val & this->state.mstatus.SXL.Mask) == 0) { + if constexpr(sizeof(reg_t) == 8) { + // Retain previous SXL and UXL value new_val |= old_val & this->state.mstatus.SXL.Mask; - } - if((new_val & this->state.mstatus.UXL.Mask) == 0) { + new_val |= old_val & this->state.mstatus.UXL.Mask; } + + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -139,10 +90,8 @@ class riscv_hart_msu_vp : public riscv_hart_common { void reset(uint64_t address) override; - iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - uint8_t* const data); - iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - const uint8_t* const data); + iss::status read(const addr_t& addr, const unsigned length, uint8_t* const data); + iss::status write(const addr_t& addr, const unsigned length, const uint8_t* const data); uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; @@ -170,14 +119,18 @@ class riscv_hart_msu_vp : public riscv_hart_common { iss::status write_edelegh(unsigned addr, uint32_t val); void check_interrupt(); - mem::mmu mmu; - mem::memory_with_htif default_mem; + mem::mmu mmu; + mem::neumann_memory_with_htif default_mem; }; -template -riscv_hart_msu_vp::riscv_hart_msu_vp() +template +riscv_hart_msu_vp::riscv_hart_msu_vp() : mmu(base::get_priv_if()) , default_mem(base::get_priv_if()) { + if constexpr(sizeof(reg_t) == 8) + // set UXL and SXL to indicate 64 bits + // FIXME: this value is not preserved in resets + this->state.mstatus.backing.val |= 0x500000000; // common regs const std::array rwaddrs{ {mepc, mtvec, mscratch, mcause, mtval, sepc, stvec, sscratch, scause, stval, sscratch, uepc, utvec, uscratch, ucause, utval}}; @@ -238,49 +191,23 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() this->csr[misa] |= (extension_encoding::S | extension_encoding::U); } -template -iss::status riscv_hart_msu_vp::read(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, uint8_t* const data) { +template +iss::status riscv_hart_msu_vp::read(const addr_t& a, const unsigned length, uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; #ifndef NDEBUG if(access && iss::access_type::DEBUG) { - CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("debug read of {} bytes @addr 0x{:x}", length, addr)); } else if(is_fetch(access)) { - CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("fetch of {} bytes @addr 0x{:x}", length, addr)); } else { - CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("read of {} bytes @addr 0x{:x}", length, addr)); } #endif try { switch(space) { - case traits::MEM: { - auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); - if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - this->fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; - return iss::Err; - } - try { - if(!is_debug(access) && (addr & (alignment - 1))) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; - this->fault_data = addr; - return iss::Err; - } - auto res = this->memory.rd_mem(access, addr, length, data); - if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { - this->reg.trap_state = (1UL << 31) | (traits::RV_CAUSE_LOAD_ACCESS << 16); - this->fault_data = addr; - } - return res; - } catch(trap_access& ta) { - if((access & access_type::DEBUG) == 0) { - this->reg.trap_state = (1UL << 31) | ta.id; - this->fault_data = ta.addr; - } - return iss::Err; - } - } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; @@ -312,8 +239,35 @@ iss::status riscv_hart_msu_vp::read(const address_type type, } else memset(data, 0, length); } break; - default: - return iss::Err; // assert("Not supported"); + default: { + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { + this->fault_data = addr; + if(is_debug(access)) + throw trap_access(0, addr); + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; + return iss::Err; + } + try { + if(!is_debug(access) && (addr & (alignment - 1))) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; + this->fault_data = addr; + return iss::Err; + } + auto res = this->memory.rd_mem({address_type::VIRTUAL, a.access, a.space, a.val}, length, data); + if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_LOAD_ACCESS << 16; + this->fault_data = addr; + } + return res; + } catch(trap_access& ta) { + if((access & access_type::DEBUG) == 0) { + this->reg.trap_state = (1UL << 31) | ta.id; + this->fault_data = ta.addr; + } + return iss::Err; + } + } break; } return iss::Ok; } catch(trap_access& ta) { @@ -325,61 +279,37 @@ iss::status riscv_hart_msu_vp::read(const address_type type, } } -template -iss::status riscv_hart_msu_vp::write(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, const uint8_t* const data) { +template +iss::status riscv_hart_msu_vp::write(const addr_t& a, const unsigned length, const uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; #ifndef NDEBUG const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; switch(length) { case 8: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 4: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 2: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 1: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, (uint16_t)data[0], addr)); break; default: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("{}write of {} bytes @addr 0x{:x}", prefix, length, addr)); } #endif try { switch(space) { - case traits::MEM: { - if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { - this->fault_data = addr; - if(access && iss::access_type::DEBUG) - throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31); // issue trap 0 - return iss::Err; - } - try { - auto alignment = std::min(length, sizeof(reg_t)); - if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_STORE << 16; - this->fault_data = addr; - return iss::Err; - } - auto res = this->memory.wr_mem(access, addr, length, data); - if(unlikely(res != iss::Ok && !is_debug(access))) { - this->reg.trap_state = (1UL << 31) | (traits::RV_CAUSE_STORE_ACCESS << 16); - this->fault_data = addr; - } - return res; - } catch(trap_access& ta) { - this->reg.trap_state = (1UL << 31) | ta.id; - this->fault_data = ta.addr; - return iss::Err; - } - } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; @@ -414,8 +344,33 @@ iss::status riscv_hart_msu_vp::write(const address_type type case traits::RES: { atomic_reservation[addr] = data[0]; } break; - default: - return iss::Err; + default: { + if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { + this->fault_data = addr; + if(access && iss::access_type::DEBUG) + throw trap_access(0, addr); + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; + return iss::Err; + } + try { + auto alignment = std::min(length, sizeof(reg_t)); + if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_STORE << 16; + this->fault_data = addr; + return iss::Err; + } + auto res = this->memory.wr_mem({address_type::VIRTUAL, a.access, a.space, a.val}, length, data); + if(unlikely(res != iss::Ok && !is_debug(access))) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_STORE_ACCESS << 16; + this->fault_data = addr; + } + return res; + } catch(trap_access& ta) { + this->reg.trap_state = (1UL << 31) | ta.id; + this->fault_data = ta.addr; + return iss::Err; + } + } break; } return iss::Ok; } catch(trap_access& ta) { @@ -427,34 +382,29 @@ iss::status riscv_hart_msu_vp::write(const address_type type } } -template -iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t& val) { +template iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t& val) { auto req_priv_lvl = (addr >> 8) & 0x3; - val = this->state.mstatus & get_mstatus_rd_mask(req_priv_lvl); + val = this->state.mstatus & base::get_msu_status_mask(req_priv_lvl); return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_status(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_status(unsigned addr, reg_t val) { auto req_priv_lvl = (addr >> 8) & 0x3; write_mstatus(val, req_priv_lvl); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_msu_vp::read_statush(unsigned addr, reg_t& val) { +template iss::status riscv_hart_msu_vp::read_statush(unsigned addr, reg_t& val) { val = this->csr[mstatush] & 0b11'1111'1000; return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_statush(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_statush(unsigned addr, reg_t val) { this->csr[mstatush] = val & 0b11'1111'1000; return iss::Ok; } -template -iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& val) { +template iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& val) { val = this->csr[mie]; if(addr < mie) val &= this->csr[mideleg]; @@ -463,16 +413,14 @@ iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_ie(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_ie(unsigned addr, reg_t val) { auto mask = riscv_hart_common::get_irq_mask((addr >> 8) & 0x3); this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& val) { +template iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& val) { val = this->csr[mip]; if(addr < mip) val &= this->csr[mideleg]; @@ -481,24 +429,21 @@ iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_ideleg(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_ideleg(unsigned addr, reg_t val) { // only U and S mode interrupts can be delegated auto mask = 0b0011'0011'0011; this->csr[mideleg] = (this->csr[mideleg] & ~mask) | (val & mask); return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_edeleg(unsigned addr, uint32_t val) { +template iss::status riscv_hart_msu_vp::write_edeleg(unsigned addr, uint32_t val) { // bit 3 (break), bit 10 (reserved), bit 11 (Ecall from M) bit 14 (reserved), bit 16-17 (reserved), bit 20-23 (reserved) uint32_t mask = 0b1111'1111'0000'1100'1011'0011'1111'0111; this->csr[arch::riscv_csr::medeleg] = (this->csr[arch::riscv_csr::medeleg] & ~mask) | (val & mask); return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_edeleg(unsigned addr, uint64_t val) { +template iss::status riscv_hart_msu_vp::write_edeleg(unsigned addr, uint64_t val) { // bit 3 (break), bit 10 (reserved), bit 11 (Ecall from M) bit 14 (reserved), bit 16-17 (reserved), bit 20-23 (reserved) uint32_t mask_lower = 0b1111'1111'0000'1100'1011'0011'1111'0111; // bit 32-47(reserved) @@ -507,22 +452,21 @@ iss::status riscv_hart_msu_vp::write_edeleg(unsigned addr, u return iss::Ok; } -template -iss::status riscv_hart_msu_vp::write_edelegh(unsigned addr, uint32_t val) { +template iss::status riscv_hart_msu_vp::write_edelegh(unsigned addr, uint32_t val) { // bit 32-47(reserved) auto mask = 0b1111'1111'1111'1111'0000'0000'0000'0000; this->csr[medelegh] = (this->csr[medelegh] & ~mask) | (val & mask); return iss::Ok; } -template inline void riscv_hart_msu_vp::reset(uint64_t address) { +template inline void riscv_hart_msu_vp::reset(uint64_t address) { BASE::reset(address); this->state.mstatus = hart_state::mstatus_reset_val; if(sizeof(reg_t) == 8) // Set UXLEN and SXLEN to 64 this->state.mstatus |= static_cast(0xa00000000ULL); } -template void riscv_hart_msu_vp::check_interrupt() { +template void riscv_hart_msu_vp::check_interrupt() { auto status = this->state.mstatus; auto ip = this->csr[mip]; auto ie = this->csr[mie]; @@ -550,8 +494,8 @@ template void riscv_hart_msu_v } } -template -uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { +template +uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // calculate and write mcause val if(flags == std::numeric_limits::max()) @@ -599,9 +543,9 @@ uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint6 // Check for semihosting call std::array data; // check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07 - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data()); + this->memory.rd_mem({address_type::VIRTUAL, access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, data.data()); addr += 8; - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data() + 4); + this->memory.rd_mem({address_type::VIRTUAL, access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, data.data() + 4); const std::array ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40}; if(data == ref_data) { @@ -613,8 +557,7 @@ uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint6 #else sprintf(buffer.data(), "0x%016lx", addr); #endif - NSCLOG(INFO, LOGCAT) << "Semihosting call at address " << buffer.data() << " occurred "; - + ILOG(disasslogger, logging::INFO, fmt::format("Semihosting call at address {} occurred ", buffer.data())); this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } @@ -676,7 +619,8 @@ uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint6 if(trap_id != 0) { if((xtvec & 0x3UL) == 3UL) { reg_t data; - auto ret = read(address_type::LOGICAL, access_type::READ, 0, this->csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); + auto ret = read({address_type::VIRTUAL, access_type::READ, traits::MEM, this->csr[mtvt]}, sizeof(reg_t), + reinterpret_cast(&data)); if(ret == iss::Err) return this->reg.PC; this->reg.NEXT_PC = data; @@ -689,18 +633,22 @@ uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint6 #else sprintf(buffer.data(), "0x%016lx", addr); #endif - if((flags & 0xffffffff) != 0xffffffff) - NSCLOG(DEBUG, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" - << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" << " at address " - << buffer.data() << " occurred, changing privilege level from " << this->lvl[this->reg.PRIV] << " to " - << this->lvl[new_priv]; + if((flags & 0xffffffff) != 0xffffffff) { + if(trap_id) { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", this->irq_str[cause], cause, buffer.data())); + } else { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Trap with cause '{}' ({}) occurred at address {}", this->trap_str[cause], cause, buffer.data())); + } + } // reset trap this->state this->reg.PRIV = new_priv; this->reg.trap_state = 0; return this->reg.NEXT_PC; } -template uint64_t riscv_hart_msu_vp::leave_trap(uint64_t flags) { +template uint64_t riscv_hart_msu_vp::leave_trap(uint64_t flags) { auto cur_priv = this->reg.PRIV; auto inst_priv = flags & 0x3; @@ -733,15 +681,15 @@ template uint64_t riscv_hart_m } // sets the pc to the value stored in the x epc register. this->reg.NEXT_PC = this->csr[uepc | inst_priv << 8]; - NSCLOG(DEBUG, LOGCAT) << "Executing xRET , changing privilege level from " << this->lvl[cur_priv] << " to " - << this->lvl[this->reg.PRIV]; + ILOG(disasslogger, logging::DEBUG, + fmt::format("Executing xRET, changing privilege level from {} to {}", this->lvl[cur_priv], this->lvl[this->reg.PRIV])); check_interrupt(); } this->reg.trap_state = this->reg.pending_trap; return this->reg.NEXT_PC; } -template void riscv_hart_msu_vp::wait_until(uint64_t flags) { +template void riscv_hart_msu_vp::wait_until(uint64_t flags) { auto status = this->state.mstatus; auto tw = status.TW; if(this->reg.PRIV < PRIV_M && tw != 0) { diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index bf5ae73..032ff17 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -42,6 +42,7 @@ #include "util/logging.h" #include #include +#include #include #include #include @@ -56,74 +57,20 @@ namespace iss { namespace arch { -template -class riscv_hart_mu_p : public riscv_hart_common { +template class riscv_hart_mu_p : public riscv_hart_common { public: using core = BASE; using base = riscv_hart_common; - using this_class = riscv_hart_mu_p; + using this_class = riscv_hart_mu_p; using reg_t = typename core::reg_t; using phys_addr_t = typename core::phys_addr_t; - static constexpr reg_t get_mstatus_mask(unsigned priv_lvl) { - if(sizeof(reg_t) == 4) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; -#else - switch(priv_lvl) { - case PRIV_U: - return FEAT & features_e::FEAT_EXT_N ? 0x00000011UL : 0UL; // 0b1...0 0001 0001 - default: - // +-SD - // | +-TSR - // | |+-TW - // | ||+-TVM - // | |||+-MXR - // | ||||+-SUM - // | |||||+-MPRV - // | |||||| +-XS - // | |||||| | +-FS - // | |||||| | | +-MPP - // | |||||| | | | +-SPP - // | |||||| | | | |+-MPIE - // | |||||| | | | || +-UPIE - // | ||||||/|/|/| || |+-MIE - // | ||||||/|/|/| || || +-UIE - return 0b10000000001000000001100010011001; - } -#endif - } else if(sizeof(reg_t) == 8) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x011ULL : priv_lvl == PRIV_S ? 0x000de133ULL : 0x007ff9ddULL; -#else - switch(priv_lvl) { - case PRIV_U: - return FEAT & features_e::FEAT_EXT_N ? 0x8000000000000011ULL : 0ULL; // 0b1...0 0001 0001 - default: - // +-TSR - // |+-TW - // ||+-TVM - // |||+-MXR - // ||||+-SUM - // |||||+-MPRV - // |||||| +-XS - // |||||| | +-FS - // |||||| | | +-MPP - // |||||| | | | +-SPP - // |||||| | | | |+-MPIE - // |||||| | | | || +-UPIE - // ||||||/|/|/| || |+-MIE - // ||||||/|/|/| || || +-UIE - return 0b00000000001000000001100010011001 | 0x8000000000000000ULL; - } -#endif - } else - assert(false && "Unsupported XLEN value"); - } - void write_mstatus(reg_t val, unsigned priv_lvl) { - auto mask = get_mstatus_mask(priv_lvl); + auto mask = base::get_mu_status_mask(priv_lvl); auto new_val = (this->state.mstatus() & ~mask) | (val & mask); + if constexpr(base::extension_status_mask) + if((new_val & base::extension_status_mask) == base::extension_status_mask) + new_val |= reg_t(1) << (sizeof(reg_t) * 8 - 1); this->state.mstatus = new_val; } @@ -133,10 +80,8 @@ class riscv_hart_mu_p : public riscv_hart_common { void reset(uint64_t address) override; - iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - uint8_t* const data); - iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, - const uint8_t* const data); + iss::status read(const addr_t& addr, const unsigned length, uint8_t* const data); + iss::status write(const addr_t& addr, const unsigned length, const uint8_t* const data); uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; @@ -149,8 +94,6 @@ class riscv_hart_mu_p : public riscv_hart_common { using mem_read_f = iss::status(iss::phys_addr_t addr, unsigned, uint8_t* const); using mem_write_f = iss::status(iss::phys_addr_t addr, unsigned, uint8_t const* const); - hart_state state; - std::unordered_map atomic_reservation; iss::status read_status(unsigned addr, reg_t& val); @@ -160,13 +103,12 @@ class riscv_hart_mu_p : public riscv_hart_common { iss::status read_ip(unsigned addr, reg_t& val); void check_interrupt(); - mem::memory_with_htif default_mem; + mem::neumann_memory_with_htif default_mem; }; -template -riscv_hart_mu_p::riscv_hart_mu_p() -: state() -, default_mem(base::get_priv_if()) { +template +riscv_hart_mu_p::riscv_hart_mu_p() +: default_mem(base::get_priv_if()) { this->csr_rd_cb[mstatus] = MK_CSR_RD_CB(read_status); this->csr_wr_cb[mstatus] = MK_CSR_WR_CB(write_status); this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); @@ -205,49 +147,24 @@ riscv_hart_mu_p::riscv_hart_mu_p() this->csr[misa] |= extension_encoding::U; } -template -iss::status riscv_hart_mu_p::read(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, uint8_t* const data) { +template +iss::status riscv_hart_mu_p::read(const addr_t& a, const unsigned length, uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; + #ifndef NDEBUG if(access && iss::access_type::DEBUG) { - CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("debug read of {} bytes @addr 0x{:x}", length, addr)); } else if(is_fetch(access)) { - CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("fetch of {} bytes @addr 0x{:x}", length, addr)); } else { - CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("read of {} bytes @addr 0x{:x}", length, addr)); } #endif try { switch(space) { - case traits::MEM: { - auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); - if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - this->fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31); // issue trap 0 - return iss::Err; - } - try { - if(!is_debug(access) && (addr & (alignment - 1))) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; - this->fault_data = addr; - return iss::Err; - } - auto res = this->memory.rd_mem(access, addr, length, data); - if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_LOAD_ACCESS << 16; - this->fault_data = addr; - } - return res; - } catch(trap_access& ta) { - if((access & access_type::DEBUG) == 0) { - this->reg.trap_state = (1UL << 31) | ta.id; - this->fault_data = ta.addr; - } - return iss::Err; - } - } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; @@ -276,8 +193,35 @@ iss::status riscv_hart_mu_p::read(const address_type type, c } else memset(data, 0, length); } break; - default: - return iss::Err; // assert("Not supported"); + default: { + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { + this->fault_data = addr; + if(is_debug(access)) + throw trap_access(0, addr); + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; + return iss::Err; + } + try { + if(!is_debug(access) && (addr & (alignment - 1))) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_LOAD << 16; + this->fault_data = addr; + return iss::Err; + } + auto res = this->memory.rd_mem({address_type::PHYSICAL, a.access, a.space, a.val}, length, data); + if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_LOAD_ACCESS << 16; + this->fault_data = addr; + } + return res; + } catch(trap_access& ta) { + if((access & access_type::DEBUG) == 0) { + this->reg.trap_state = (1UL << 31) | ta.id; + this->fault_data = ta.addr; + } + return iss::Err; + } + } break; } return iss::Ok; } catch(trap_access& ta) { @@ -289,40 +233,66 @@ iss::status riscv_hart_mu_p::read(const address_type type, c } } -template -iss::status riscv_hart_mu_p::write(const address_type type, const access_type access, const uint32_t space, - const uint64_t addr, const unsigned length, const uint8_t* const data) { +template +iss::status riscv_hart_mu_p::write(const addr_t& a, const unsigned length, const uint8_t* const data) { + auto& addr = a.val; + auto& space = a.space; + auto& access = a.access; + auto& type = a.type; #ifndef NDEBUG const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; switch(length) { case 8: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 4: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 2: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, *reinterpret_cast(&data[0]), addr)); break; case 1: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" - << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, + fmt::format("{}write of {} bytes (0x{:x}) @addr 0x{:x}", prefix, length, (uint16_t)data[0], addr)); break; default: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr 0x" << std::hex << addr; + ILOG(isslogger, logging::TRACEALL, fmt::format("{}write of {} bytes @addr 0x{:x}", prefix, length, addr)); } #endif try { switch(space) { - case traits::MEM: { + case traits::CSR: { + if(length != sizeof(reg_t)) + return iss::Err; + auto res = this->write_csr(addr, *reinterpret_cast(data)); + if(res != iss::Ok && !is_debug(access)) + this->reg.trap_state = (1U << 31) | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; + return res; + } break; + case traits::FENCE: { + switch(addr) { + case traits::fence: + case traits::fencei: + break; + case traits::fencevma: { + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; + } + default: + return iss::Ok; + } + } + case traits::RES: { + atomic_reservation[addr] = data[0]; + } break; + default: { if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); - this->reg.trap_state = (1UL << 31); // issue trap 0 + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; return iss::Err; } try { @@ -332,7 +302,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, this->fault_data = addr; return iss::Err; } - auto res = this->memory.wr_mem(access, addr, length, data); + auto res = this->memory.wr_mem({address_type::PHYSICAL, a.access, a.space, a.val}, length, data); if(unlikely(res != iss::Ok && !is_debug(access))) { this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_STORE_ACCESS << 16; this->fault_data = addr; @@ -344,31 +314,6 @@ iss::status riscv_hart_mu_p::write(const address_type type, return iss::Err; } } break; - case traits::CSR: { - if(length != sizeof(reg_t)) - return iss::Err; - auto res = this->write_csr(addr, *reinterpret_cast(data)); - if(res != iss::Ok && !is_debug(access)) - this->reg.trap_state = (1U << 31) | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; - return res; - } break; - case traits::FENCE: { - switch(addr) { - case traits::fence: - case traits::fencei: - break; - case traits::fencevma: { - this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; - } - default: - return iss::Ok; - } - } - case traits::RES: { - atomic_reservation[addr] = data[0]; - } break; - default: - return iss::Err; } return iss::Ok; } catch(trap_access& ta) { @@ -380,47 +325,42 @@ iss::status riscv_hart_mu_p::write(const address_type type, } } -template -iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t& val) { - val = state.mstatus & get_mstatus_mask((addr >> 8) & 0x3); +template iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t& val) { + val = this->state.mstatus & base::get_mu_status_mask((addr >> 8) & 0x3); return iss::Ok; } -template -iss::status riscv_hart_mu_p::write_status(unsigned addr, reg_t val) { +template iss::status riscv_hart_mu_p::write_status(unsigned addr, reg_t val) { write_mstatus(val, (addr >> 8) & 0x3); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t& val) { +template iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t& val) { auto mask = riscv_hart_common::get_irq_mask((addr >> 8) & 0x3); val = this->csr[mie] & mask; return iss::Ok; } -template -iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t val) { +template iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t val) { auto mask = riscv_hart_common::get_irq_mask((addr >> 8) & 0x3); this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } -template -iss::status riscv_hart_mu_p::read_ip(unsigned addr, reg_t& val) { +template iss::status riscv_hart_mu_p::read_ip(unsigned addr, reg_t& val) { auto mask = riscv_hart_common::get_irq_mask((addr >> 8) & 0x3); val = this->csr[mip] & mask; return iss::Ok; } -template inline void riscv_hart_mu_p::reset(uint64_t address) { +template inline void riscv_hart_mu_p::reset(uint64_t address) { BASE::reset(address); - state.mstatus = hart_state::mstatus_reset_val; + this->state.mstatus = hart_state::mstatus_reset_val; } -template void riscv_hart_mu_p::check_interrupt() { +template void riscv_hart_mu_p::check_interrupt() { // TODO: Implement CLIC functionality // Multiple simultaneous interrupts and traps at the same privilege level are // handled in the following decreasing priority order: @@ -428,7 +368,7 @@ template void riscv_hart_mu_p< // any synchronous traps. auto ena_irq = this->csr[mip] & this->csr[mie]; - bool mstatus_mie = state.mstatus.MIE; + bool mstatus_mie = this->state.mstatus.MIE; auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie; auto enabled_interrupts = m_enabled ? ena_irq : 0; @@ -442,8 +382,7 @@ template void riscv_hart_mu_p< } } -template -uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) { +template uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) { // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // calculate and write mcause val if(flags == std::numeric_limits::max()) @@ -485,9 +424,11 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ // Check for semihosting call std::array data; // check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07 - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data()); + this->memory.rd_mem({iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, + data.data()); addr += 8; - this->memory.rd_mem(iss::access_type::DEBUG_READ, addr - 4, 4, data.data() + 4); + this->memory.rd_mem({iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, traits::IMEM, addr - 4}, 4, + data.data() + 4); const std::array ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40}; if(data == ref_data) { @@ -499,8 +440,7 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ #else sprintf(buffer.data(), "0x%016lx", addr); #endif - NSCLOG(INFO, LOGCAT) << "Semihosting call at address " << buffer.data() << " occurred "; - + ILOG(disasslogger, logging::INFO, fmt::format("Semihosting call at address {} occurred ", buffer.data())); this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } @@ -532,13 +472,13 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ // store the actual privilege level in yPP and store interrupt enable flags switch(new_priv) { case PRIV_M: - state.mstatus.MPP = this->reg.PRIV; - state.mstatus.MPIE = state.mstatus.MIE; - state.mstatus.MIE = false; + this->state.mstatus.MPP = this->reg.PRIV; + this->state.mstatus.MPIE = this->state.mstatus.MIE; + this->state.mstatus.MIE = false; break; case PRIV_U: - state.mstatus.UPIE = state.mstatus.UIE; - state.mstatus.UIE = false; + this->state.mstatus.UPIE = this->state.mstatus.UIE; + this->state.mstatus.UIE = false; break; default: break; @@ -552,7 +492,8 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ if(trap_id != 0) { if((xtvec & 0x3UL) == 3UL) { reg_t data; - auto ret = read(address_type::LOGICAL, access_type::READ, 0, this->csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); + auto ret = read({address_type::PHYSICAL, access_type::READ, traits::MEM, this->csr[mtvt]}, sizeof(reg_t), + reinterpret_cast(&data)); if(ret == iss::Err) return this->reg.PC; this->reg.NEXT_PC = data; @@ -565,52 +506,56 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ #else sprintf(buffer.data(), "0x%016lx", addr); #endif - if((flags & 0xffffffff) != 0xffffffff) - NSCLOG(DEBUG, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" - << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" << " at address " - << buffer.data() << " occurred, changing privilege level from " << this->lvl[this->reg.PRIV] << " to " - << this->lvl[new_priv]; + if((flags & 0xffffffff) != 0xffffffff) { + if(trap_id) { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", this->irq_str[cause], cause, buffer.data())); + } else { + ILOG(disasslogger, logging::DEBUG, + fmt::format("Trap with cause '{}' ({}) occurred at address {}", this->trap_str[cause], cause, buffer.data())); + } + } // reset trap state this->reg.PRIV = new_priv; this->reg.trap_state = 0; return this->reg.NEXT_PC; } -template uint64_t riscv_hart_mu_p::leave_trap(uint64_t flags) { +template uint64_t riscv_hart_mu_p::leave_trap(uint64_t flags) { auto cur_priv = this->reg.PRIV; auto inst_priv = (flags & 0x3) ? 3 : 0; if(inst_priv > cur_priv) { this->reg.trap_state = 0x80ULL << 24 | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; this->reg.NEXT_PC = std::numeric_limits::max(); } else { - auto status = state.mstatus; + auto status = this->state.mstatus; // pop the relevant lower-privilege interrupt enable and privilege mode stack // clear respective yIE switch(inst_priv) { case PRIV_M: - this->reg.PRIV = state.mstatus.MPP; - state.mstatus.MPP = 0; // clear mpp to U mode - state.mstatus.MIE = state.mstatus.MPIE; - state.mstatus.MPIE = 1; + this->reg.PRIV = this->state.mstatus.MPP; + this->state.mstatus.MPP = 0; // clear mpp to U mode + this->state.mstatus.MIE = this->state.mstatus.MPIE; + this->state.mstatus.MPIE = 1; break; case PRIV_U: this->reg.PRIV = 0; - state.mstatus.UIE = state.mstatus.UPIE; - state.mstatus.UPIE = 1; + this->state.mstatus.UIE = this->state.mstatus.UPIE; + this->state.mstatus.UPIE = 1; break; } // sets the pc to the value stored in the x epc register. this->reg.NEXT_PC = this->csr[uepc | inst_priv << 8]; - NSCLOG(DEBUG, LOGCAT) << "Executing xRET , changing privilege level from " << this->lvl[cur_priv] << " to " - << this->lvl[this->reg.PRIV]; + ILOG(disasslogger, logging::DEBUG, + fmt::format("Executing xRET, changing privilege level from {} to {}", this->lvl[cur_priv], this->lvl[this->reg.PRIV])); check_interrupt(); } this->reg.trap_state = this->reg.pending_trap; return this->reg.NEXT_PC; } -template void riscv_hart_mu_p::wait_until(uint64_t flags) { - auto status = state.mstatus; +template void riscv_hart_mu_p::wait_until(uint64_t flags) { + auto status = this->state.mstatus; auto tw = status.TW; if(this->reg.PRIV == PRIV_S && tw != 0) { this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_ILLEGAL_INSTRUCTION << 16; diff --git a/src/iss/arch/rv32gc.h b/src/iss/arch/rv32gc.h index 453139f..4f54b68 100644 --- a/src/iss/arch/rv32gc.h +++ b/src/iss/arch/rv32gc.h @@ -287,10 +287,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=32ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=32ULL, FLEN=64ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL, FFLAG_MASK=31ULL, MISA_VAL=1073746221ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL @@ -477,8 +477,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + 4294967296, + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = 4294967296; + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv32gcv.h b/src/iss/arch/rv32gcv.h index cb17465..2680cba 100644 --- a/src/iss/arch/rv32gcv.h +++ b/src/iss/arch/rv32gcv.h @@ -324,10 +324,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=32ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=32ULL, FLEN=64ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL, FFLAG_MASK=31ULL, VLEN=256ULL, ELEN=32ULL, EEW_MAX=32ULL, @@ -591,8 +591,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + 4294967296, + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = 4294967296; + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv32i.h b/src/iss/arch/rv32i.h index 42d507f..1a81b3f 100644 --- a/src/iss/arch/rv32i.h +++ b/src/iss/arch/rv32i.h @@ -254,10 +254,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=32ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=32ULL, FLEN=0ULL, INSTR_ALIGNMENT=4ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MISA_VAL=1073742080ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL @@ -378,8 +378,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + 4294967296, + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = 4294967296; + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv32imac.h b/src/iss/arch/rv32imac.h index 1e0bdb9..ba90c01 100644 --- a/src/iss/arch/rv32imac.h +++ b/src/iss/arch/rv32imac.h @@ -254,10 +254,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=32ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=32ULL, FLEN=0ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL, MISA_VAL=1073746181ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL @@ -378,8 +378,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + 4294967296, + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = 4294967296; + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv32imc.h b/src/iss/arch/rv32imc.h deleted file mode 100644 index 488afb9..0000000 --- a/src/iss/arch/rv32imc.h +++ /dev/null @@ -1,263 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2017 - 2021 MINRES Technologies GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - *******************************************************************************/ - -#ifndef _rv32imc_H_ -#define _rv32imc_H_ -// clang-format off -#include -#include -#include -#include - -namespace iss { -namespace arch { - -struct rv32imc; - -template <> struct traits { - - constexpr static char const* const core_type = "rv32imc"; - - static constexpr std::array reg_names{ - {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc", "next_pc", "priv", "dpc"}}; - - static constexpr std::array reg_aliases{ - {"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc", "next_pc", "priv", "dpc"}}; - - enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, CLIC_NUM_IRQ=0ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL}; - - constexpr static unsigned FP_REGS_SIZE = 0; - - enum reg_e { - X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH - }; - - using reg_t = uint32_t; - - using addr_t = uint32_t; - - using code_word_t = uint32_t; //TODO: check removal - - using virt_addr_t = iss::typed_addr_t; - - using phys_addr_t = iss::typed_addr_t; - - static constexpr std::array reg_bit_widths{ - {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64,32,32}}; - - static constexpr std::array reg_byte_offsets{ - {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}}; - - static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); - - enum sreg_flag_e { FLAGS }; - - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; - - enum class opcode_e { - LUI = 0, - AUIPC = 1, - JAL = 2, - JALR = 3, - BEQ = 4, - BNE = 5, - BLT = 6, - BGE = 7, - BLTU = 8, - BGEU = 9, - LB = 10, - LH = 11, - LW = 12, - LBU = 13, - LHU = 14, - SB = 15, - SH = 16, - SW = 17, - ADDI = 18, - SLTI = 19, - SLTIU = 20, - XORI = 21, - ORI = 22, - ANDI = 23, - SLLI = 24, - SRLI = 25, - SRAI = 26, - ADD = 27, - SUB = 28, - SLL = 29, - SLT = 30, - SLTU = 31, - XOR = 32, - SRL = 33, - SRA = 34, - OR = 35, - AND = 36, - FENCE = 37, - ECALL = 38, - EBREAK = 39, - MRET = 40, - WFI = 41, - CSRRW = 42, - CSRRS = 43, - CSRRC = 44, - CSRRWI = 45, - CSRRSI = 46, - CSRRCI = 47, - FENCE_I = 48, - MUL = 49, - MULH = 50, - MULHSU = 51, - MULHU = 52, - DIV = 53, - DIVU = 54, - REM = 55, - REMU = 56, - C__ADDI4SPN = 57, - C__LW = 58, - C__SW = 59, - C__ADDI = 60, - C__NOP = 61, - C__JAL = 62, - C__LI = 63, - C__LUI = 64, - C__ADDI16SP = 65, - __reserved_clui = 66, - C__SRLI = 67, - C__SRAI = 68, - C__ANDI = 69, - C__SUB = 70, - C__XOR = 71, - C__OR = 72, - C__AND = 73, - C__J = 74, - C__BEQZ = 75, - C__BNEZ = 76, - C__SLLI = 77, - C__LWSP = 78, - C__MV = 79, - C__JR = 80, - __reserved_cmv = 81, - C__ADD = 82, - C__JALR = 83, - C__EBREAK = 84, - C__SWSP = 85, - DII = 86, - MAX_OPCODE - }; -}; - -struct rv32imc: public arch_if { - - using virt_addr_t = typename traits::virt_addr_t; - using phys_addr_t = typename traits::phys_addr_t; - using reg_t = typename traits::reg_t; - using addr_t = typename traits::addr_t; - - rv32imc(); - ~rv32imc(); - - void reset(uint64_t address=0) override; - - uint8_t* get_regs_base_ptr() override; - - inline uint64_t get_icount() { return reg.icount; } - - inline bool should_stop() { return interrupt_sim; } - - inline uint64_t stop_code() { return interrupt_sim; } - - virtual phys_addr_t virt2phys(const iss::addr_t& addr); - - virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } - - inline uint32_t get_last_branch() { return reg.last_branch; } - - -#pragma pack(push, 1) - struct rv32imc_regs { - uint32_t X0 = 0; - uint32_t X1 = 0; - uint32_t X2 = 0; - uint32_t X3 = 0; - uint32_t X4 = 0; - uint32_t X5 = 0; - uint32_t X6 = 0; - uint32_t X7 = 0; - uint32_t X8 = 0; - uint32_t X9 = 0; - uint32_t X10 = 0; - uint32_t X11 = 0; - uint32_t X12 = 0; - uint32_t X13 = 0; - uint32_t X14 = 0; - uint32_t X15 = 0; - uint32_t X16 = 0; - uint32_t X17 = 0; - uint32_t X18 = 0; - uint32_t X19 = 0; - uint32_t X20 = 0; - uint32_t X21 = 0; - uint32_t X22 = 0; - uint32_t X23 = 0; - uint32_t X24 = 0; - uint32_t X25 = 0; - uint32_t X26 = 0; - uint32_t X27 = 0; - uint32_t X28 = 0; - uint32_t X29 = 0; - uint32_t X30 = 0; - uint32_t X31 = 0; - uint32_t PC = 0; - uint32_t NEXT_PC = 0; - uint8_t PRIV = 0; - uint32_t DPC = 0; - uint32_t trap_state = 0, pending_trap = 0; - uint64_t icount = 0; - uint64_t cycle = 0; - uint64_t instret = 0; - uint32_t instruction = 0; - uint32_t last_branch = 0; - } reg; -#pragma pack(pop) - std::array addr_mode; - - uint64_t interrupt_sim=0; - - uint32_t get_fcsr(){return 0;} - void set_fcsr(uint32_t val){} - -}; - -} -} -#endif /* _rv32imc_H_ */ -// clang-format on diff --git a/src/iss/arch/rv64gc.h b/src/iss/arch/rv64gc.h index d76cdd2..f78ae2e 100644 --- a/src/iss/arch/rv64gc.h +++ b/src/iss/arch/rv64gc.h @@ -287,10 +287,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=64ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=64ULL, FLEN=64ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=128ULL, FFLAG_MASK=31ULL, MISA_VAL=9223372036854780205ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL @@ -477,8 +477,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + std::numeric_limits::max(), + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = std::numeric_limits::max(); + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv64gcv.h b/src/iss/arch/rv64gcv.h index fc8f49a..7ffc113 100644 --- a/src/iss/arch/rv64gcv.h +++ b/src/iss/arch/rv64gcv.h @@ -324,10 +324,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=64ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=64ULL, FLEN=64ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=128ULL, FFLAG_MASK=31ULL, VLEN=512ULL, ELEN=64ULL, EEW_MAX=64ULL, @@ -591,8 +591,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + std::numeric_limits::max(), + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = std::numeric_limits::max(); + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/rv64i.h b/src/iss/arch/rv64i.h index 664f28c..76df877 100644 --- a/src/iss/arch/rv64i.h +++ b/src/iss/arch/rv64i.h @@ -254,10 +254,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=64ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=64ULL, FLEN=0ULL, INSTR_ALIGNMENT=4ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MISA_VAL=2147483904ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL @@ -378,8 +378,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + std::numeric_limits::max(), + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = std::numeric_limits::max(); + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/arch/tgc5c.h b/src/iss/arch/tgc5c.h index 3ce02ec..a07cc99 100644 --- a/src/iss/arch/tgc5c.h +++ b/src/iss/arch/tgc5c.h @@ -254,10 +254,10 @@ template <> struct traits { RV_IRQ_VS_SOFT=2ULL, RV_IRQ_M_SOFT=3ULL, RV_IRQ_U_TIMER=4ULL, RV_IRQ_S_TIMER=5ULL, RV_IRQ_VS_TIMER=6ULL, RV_IRQ_M_TIMER=7ULL, RV_IRQ_U_EXT=8ULL, RV_IRQ_S_EXT=9ULL, RV_IRQ_VS_EXT=10ULL, RV_IRQ_M_EXT=11ULL, RV_IRQ_S_GEXT=12ULL, RV_IRQ_COP=12ULL, - RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=1ULL, RV_MIP_VSSIP=1ULL, - RV_MIP_MSIP=1ULL, RV_MIP_UTIP=1ULL, RV_MIP_STIP=1ULL, RV_MIP_VSTIP=1ULL, - RV_MIP_MTIP=1ULL, RV_MIP_UEIP=1ULL, RV_MIP_SEIP=1ULL, RV_MIP_VSEIP=1ULL, - RV_MIP_MEIP=1ULL, RV_MIP_SGEIP=1ULL, RV_MIP_LCOFIP=1ULL, XLEN=32ULL, + RV_IRQ_LCOF=13ULL, RV_MIP_USIP=1ULL, RV_MIP_SSIP=2ULL, RV_MIP_VSSIP=4ULL, + RV_MIP_MSIP=8ULL, RV_MIP_UTIP=16ULL, RV_MIP_STIP=32ULL, RV_MIP_VSTIP=64ULL, + RV_MIP_MTIP=128ULL, RV_MIP_UEIP=256ULL, RV_MIP_SEIP=512ULL, RV_MIP_VSEIP=1024ULL, + RV_MIP_MEIP=2048ULL, RV_MIP_SGEIP=4096ULL, RV_MIP_LCOFIP=8192ULL, XLEN=32ULL, FLEN=0ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL, MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, CLIC_NUM_IRQ=0ULL @@ -378,8 +378,17 @@ template <> struct traits { enum sreg_flag_e { FLAGS }; - enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = MEM }; + enum mem_type_e { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max()}; + static constexpr std::array mem_sizes{{ + 4294967296, + 8, + 8, + 4096 + }}; + + static constexpr uint64_t max_mem_size = 4294967296; + enum class opcode_e { LUI = 0, AUIPC = 1, diff --git a/src/iss/debugger/riscv_target_adapter.h b/src/iss/debugger/riscv_target_adapter.h index 5b8e166..be2b75b 100644 --- a/src/iss/debugger/riscv_target_adapter.h +++ b/src/iss/debugger/riscv_target_adapter.h @@ -267,13 +267,13 @@ template status riscv_target_adapter::write_single_registe } template status riscv_target_adapter::read_mem(uint64_t addr, std::vector& data) { - auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr}); + auto a = map_addr({iss::address_type::VIRTUAL, iss::access_type::DEBUG_READ, 0, addr}); auto f = [&]() -> status { return core->read(a, data.size(), data.data()); }; return srv->execute_syncronized(f); } template status riscv_target_adapter::write_mem(uint64_t addr, const std::vector& data) { - auto a = map_addr({iss::access_type::DEBUG_WRITE, iss::address_type::VIRTUAL, 0, addr}); + auto a = map_addr({iss::address_type::VIRTUAL, iss::access_type::DEBUG_WRITE, 0, addr}); auto f = [&]() -> status { return core->write(a, data.size(), data.data()); }; return srv->execute_syncronized(f); } @@ -322,8 +322,8 @@ template status riscv_target_adapter::add_break(break_type return Err; case SW_EXEC: case HW_EXEC: { - auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); - auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length}); + auto saddr = map_addr({iss::address_type::PHYSICAL, iss::access_type::FETCH, 0, addr}); + auto eaddr = map_addr({iss::address_type::PHYSICAL, iss::access_type::FETCH, 0, addr + length}); target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val); CPPLOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val << std::dec; @@ -339,7 +339,7 @@ template status riscv_target_adapter::remove_break(break_t return Err; case SW_EXEC: case HW_EXEC: { - auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); + auto saddr = map_addr({iss::address_type::PHYSICAL, iss::access_type::FETCH, 0, addr}); unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val); if(handle) { CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec; diff --git a/src/iss/mem/memory_if.h b/src/iss/mem/memory_if.h index 8d6e8b7..48cfea2 100644 --- a/src/iss/mem/memory_if.h +++ b/src/iss/mem/memory_if.h @@ -46,12 +46,12 @@ namespace iss { namespace mem { -using rd_mem_func_sig = iss::status(iss::access_type, uint64_t, unsigned, uint8_t*); -using wr_mem_func_sig = iss::status(iss::access_type, uint64_t, unsigned, uint8_t const*); +using rd_mem_func_sig = iss::status(const addr_t& addr, unsigned length, uint8_t* data); +using wr_mem_func_sig = iss::status(const addr_t& addr, unsigned length, uint8_t const* data); struct memory_if { - util::delegate rd_mem; - util::delegate wr_mem; + util::delegate rd_mem; + util::delegate wr_mem; }; struct memory_elem { diff --git a/src/iss/mem/memory_with_htif.h b/src/iss/mem/memory_with_htif.h index 47b021f..e78d718 100644 --- a/src/iss/mem/memory_with_htif.h +++ b/src/iss/mem/memory_with_htif.h @@ -36,22 +36,24 @@ #define _MEMORY_WITH_HTIF_ #include "iss/arch/riscv_hart_common.h" +#include "iss/arch/traits.h" #include "iss/vm_types.h" #include "memory_if.h" +#include #include #include #include namespace iss { namespace mem { -template struct memory_with_htif : public memory_elem { - using this_class = memory_with_htif; - constexpr static unsigned WORD_LEN = sizeof(WORD_TYPE) * 8; +template struct neumann_memory_with_htif : public memory_elem { + using this_class = neumann_memory_with_htif; + using reg_t = typename PLAT::reg_t; - memory_with_htif(arch::priv_if hart_if) + neumann_memory_with_htif(arch::priv_if hart_if) : hart_if(hart_if) {} - ~memory_with_htif() = default; + ~neumann_memory_with_htif() = default; memory_if get_mem_if() override { return memory_if{.rd_mem{util::delegate::from(this)}, @@ -59,21 +61,21 @@ template struct memory_with_htif : public memory_elem { } void set_next(memory_if) override { - // intenrionally left empty, leaf element + // intentionally left empty, leaf element } private: - iss::status read_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t* data) { - // for(auto offs = 0U; offs < length; ++offs) { - // *(data + offs) = mem[(addr + offs) % mem.size()]; - // } - if(mem.is_allocated(addr)) { - const auto& p = mem(addr / mem.page_size); - auto offs = addr & mem.page_addr_mask; + iss::status read_mem(const iss::addr_t& addr, unsigned length, uint8_t* data) { + assert((addr.type == iss::address_type::PHYSICAL || is_debug(addr.access)) && + "Only physical addresses are expected in memory_with_htif"); + mem_type& mem = addr.space == iss::arch::traits::IMEM ? memories[iss::arch::traits::MEM] : memories[addr.space]; + if(mem.is_allocated(addr.val)) { + const auto& p = mem(addr.val / mem.page_size); + auto offs = addr.val & mem.page_addr_mask; if((offs + length) > mem.page_size) { auto first_part = mem.page_size - offs; std::copy(p.data() + offs, p.data() + offs + first_part, data); - const auto& p2 = mem((addr / mem.page_size) + 1); + const auto& p2 = mem((addr.val / mem.page_size) + 1); std::copy(p2.data(), p2.data() + length - first_part, data + first_part); } else { std::copy(p.data() + offs, p.data() + offs + length, data); @@ -86,29 +88,34 @@ template struct memory_with_htif : public memory_elem { return iss::Ok; } - iss::status write_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t const* data) { - auto& p = mem(addr / mem.page_size); - auto offs = addr & mem.page_addr_mask; + iss::status write_mem(const iss::addr_t& addr, unsigned length, uint8_t const* data) { + assert((addr.type == iss::address_type::PHYSICAL || is_debug(addr.access)) && + "Only physical addresses are expected in memory_with_htif"); + mem_type& mem = addr.space == iss::arch::traits::IMEM ? memories[iss::arch::traits::MEM] : memories[addr.space]; + auto& p = mem(addr.val / mem.page_size); + auto offs = addr.val & mem.page_addr_mask; if((offs + length) > mem.page_size) { auto first_part = mem.page_size - offs; std::copy(data, data + first_part, p.data() + offs); - auto& p2 = mem((addr / mem.page_size) + 1); + auto& p2 = mem((addr.val / mem.page_size) + 1); std::copy(data + first_part, data + length, p2.data()); } else { std::copy(data, data + length, p.data() + offs); } - // this->tohost handling in case of riscv-test - // according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754: - if(access && iss::access_type::FUNC && addr == hart_if.tohost) { + if(addr.val == hart_if.tohost) { return hart_if.exec_htif(data, length); } return iss::Ok; } protected: - using mem_type = util::sparse_array; - mem_type mem; - arch::priv_if hart_if; + // Currently no type erasure for the sparse_array is available, so all memories + // have the largest possible size. Memory footprint should still be small as it + // a sparse array + using mem_type = util::sparse_array < uint8_t, + arch::traits::max_mem_size<1ull << 36 ? arch::traits::max_mem_size : (1ull << 36)>; + std::array::mem_sizes.size()> memories{}; + arch::priv_if hart_if; }; } // namespace mem } // namespace iss diff --git a/src/iss/mem/mmu.h b/src/iss/mem/mmu.h index 93e18e0..7232cbd 100644 --- a/src/iss/mem/mmu.h +++ b/src/iss/mem/mmu.h @@ -33,6 +33,7 @@ ******************************************************************************/ #include "iss/arch/riscv_hart_common.h" +#include "iss/arch/traits.h" #include "iss/arch_if.h" #include "iss/vm_types.h" #include "memory_if.h" @@ -68,14 +69,14 @@ struct vm_info { uint64_t ptbase; }; -template struct mmu : public memory_elem { - using this_class = mmu; - using reg_t = WORD_TYPE; +template struct mmu : public memory_elem { + using this_class = mmu; + using reg_t = typename PLAT::reg_t; constexpr static reg_t PGSIZE = 1 << PGSHIFT; constexpr static reg_t PGMASK = PGSIZE - 1; - mmu(arch::priv_if hart_if) + mmu(arch::priv_if hart_if) : hart_if(hart_if) { hart_if.csr_rd_cb[arch::riscv_csr::satp] = MK_CSR_RD_CB(read_satp); hart_if.csr_wr_cb[arch::riscv_csr::satp] = MK_CSR_WR_CB(write_satp); @@ -103,32 +104,45 @@ template struct mmu : public memory_elem { return priv; } - bool needs_translation(iss::access_type type) { - return (effective_priv(type) == arch::PRIV_U || effective_priv(type) == arch::PRIV_S) && vm_setting.levels; + bool needs_translation(const addr_t& addr) { + return likely(addr.space == arch::traits::MEM) && + (effective_priv(addr.access) == arch::PRIV_U || effective_priv(addr.access) == arch::PRIV_S) && vm_setting.levels; } - iss::status read_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t* data) { - if(unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK) && needs_translation(access))) { // we may cross a page boundary - auto split_addr = (addr + length) & ~PGMASK; - auto len1 = split_addr - addr; - auto res = down_stream_mem.rd_mem(access, virt2phys(access, addr), len1, data); + iss::status read_mem(const addr_t& addr, unsigned length, uint8_t* data) { + assert((addr.type == iss::address_type::VIRTUAL || is_debug(addr.access)) && "Only virtual addresses are expected in mmu"); + if(unlikely((addr.val & ~PGMASK) != ((addr.val + length - 1) & ~PGMASK) && + needs_translation(addr))) { // we may cross a page boundary + auto split_addr = (addr.val + length) & ~PGMASK; + auto len1 = split_addr - addr.val; + auto res = down_stream_mem.rd_mem({iss::address_type::PHYSICAL, addr.access, addr.space, virt2phys(addr.access, addr.val)}, + len1, data); if(res == iss::Ok) - res = down_stream_mem.rd_mem(access, virt2phys(access, split_addr), length - len1, data + len1); + res = down_stream_mem.rd_mem({iss::address_type::PHYSICAL, addr.access, addr.space, virt2phys(addr.access, addr.val)}, + length - len1, data + len1); return res; } - return down_stream_mem.rd_mem(access, needs_translation(access) ? virt2phys(access, addr) : addr, length, data); + return down_stream_mem.rd_mem( + {iss::address_type::PHYSICAL, addr.access, addr.space, needs_translation(addr) ? virt2phys(addr.access, addr.val) : addr.val}, + length, data); } - iss::status write_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t const* data) { - if(unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK) && needs_translation(access))) { // we may cross a page boundary - auto split_addr = (addr + length) & ~PGMASK; - auto len1 = split_addr - addr; - auto res = down_stream_mem.wr_mem(access, virt2phys(access, addr), len1, data); + iss::status write_mem(const addr_t& addr, unsigned length, uint8_t const* data) { + assert((addr.type == iss::address_type::VIRTUAL || is_debug(addr.access)) && "Only virtual addresses are expected in mmu"); + if(unlikely((addr.val & ~PGMASK) != ((addr.val + length - 1) & ~PGMASK) && + needs_translation(addr))) { // we may cross a page boundary + auto split_addr = (addr.val + length) & ~PGMASK; + auto len1 = split_addr - addr.val; + auto res = down_stream_mem.wr_mem({iss::address_type::PHYSICAL, addr.access, addr.space, virt2phys(addr.access, addr.val)}, + len1, data); if(res == iss::Ok) - res = down_stream_mem.wr_mem(access, virt2phys(access, split_addr), length - len1, data + len1); + res = down_stream_mem.wr_mem({iss::address_type::PHYSICAL, addr.access, addr.space, virt2phys(addr.access, split_addr)}, + length - len1, data + len1); return res; } - return down_stream_mem.wr_mem(access, needs_translation(access) ? virt2phys(access, addr) : addr, length, data); + return down_stream_mem.wr_mem( + {iss::address_type::PHYSICAL, addr.access, addr.space, needs_translation(addr) ? virt2phys(addr.access, addr.val) : addr.val}, + length, data); } iss::status read_plain(unsigned addr, reg_t& val) { @@ -215,11 +229,11 @@ template struct mmu : public memory_elem { reg_t satp; std::unordered_map tlb; vm_info vm_setting{0, 0, 0, 0}; - arch::priv_if hart_if; + arch::priv_if hart_if; memory_if down_stream_mem; }; -template uint64_t mmu::virt2phys(iss::access_type access, uint64_t addr) { +template uint64_t mmu::virt2phys(iss::access_type access, uint64_t addr) { const auto type = access & iss::access_type::FUNC; reg_t pte{0}; if(auto it = tlb.find(addr >> PGSHIFT); it != tlb.end()) { @@ -237,8 +251,9 @@ template uint64_t mmu::virt2phys(iss::access_typ for(int i = vm_setting.levels - 1; i >= 0; i--) { const int ptshift = i * vm_setting.idxbits; const reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm_setting.idxbits) - 1); - const iss::status res = - down_stream_mem.rd_mem(iss::access_type::READ, base + idx * vm_setting.ptesize, vm_setting.ptesize, (uint8_t*)&pte); + const iss::status res = down_stream_mem.rd_mem( + {iss::address_type::PHYSICAL, iss::access_type::READ, arch::traits::MEM, base + idx * vm_setting.ptesize}, + vm_setting.ptesize, (uint8_t*)&pte); if(res != iss::status::Ok) { CPPLOG(DEBUG) << "Access fault when trying to read next pte"; switch(type) { diff --git a/src/iss/mem/pmp.h b/src/iss/mem/pmp.h index 6056c44..bc3a17c 100644 --- a/src/iss/mem/pmp.h +++ b/src/iss/mem/pmp.h @@ -32,9 +32,10 @@ * eyck@minres.com - initial implementation ******************************************************************************/ -#include "memory_if.h" #include "iss/arch/riscv_hart_common.h" +#include "iss/arch/traits.h" #include "iss/vm_types.h" +#include "memory_if.h" #include namespace iss { @@ -89,12 +90,11 @@ inline void write_reg_with_offset(uint32_t& reg, uint8_t offs, const uint8_t* co } } -template struct pmp : public memory_elem { - using this_class = pmp; - using reg_t = WORD_TYPE; - constexpr static unsigned WORD_LEN = sizeof(WORD_TYPE) * 8; +template struct pmp : public memory_elem { + using this_class = pmp; + using reg_t = typename PLAT::reg_t; - pmp(arch::priv_if hart_if) + pmp(arch::priv_if hart_if) : hart_if(hart_if) { for(size_t i = arch::pmpaddr0; i <= arch::pmpaddr15; ++i) { hart_if.csr_rd_cb[i] = MK_CSR_RD_CB(read_plain); @@ -116,26 +116,28 @@ template struct pmp : public memory_elem { void set_next(memory_if mem) override { down_stream_mem = mem; } private: - iss::status read_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t* data) { - if(!pmp_check(access, addr, length) && !is_debug(access)) { + iss::status read_mem(const addr_t& addr, unsigned length, uint8_t* data) { + assert((addr.type == iss::address_type::PHYSICAL || is_debug(addr.access)) && "Only physical addresses are expected in pmp"); + if(likely(addr.space == arch::traits::MEM) && !pmp_check(addr.access, addr.val, length) && !is_debug(addr.access)) { hart_if.fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); - hart_if.reg.trap_state = (1UL << 31) | ((access == access_type::FETCH ? 1 : 5) << 16); // issue trap 1 + if(is_debug(addr.access)) + throw trap_access(0, addr.val); + hart_if.reg.trap_state = (1UL << 31) | ((addr.access == access_type::FETCH ? 1 : 5) << 16); // issue trap 1 return iss::Err; } - return down_stream_mem.rd_mem(access, addr, length, data); + return down_stream_mem.rd_mem(addr, length, data); } - iss::status write_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t const* data) { - if(!pmp_check(access, addr, length) && !is_debug(access)) { + iss::status write_mem(const addr_t& addr, unsigned length, uint8_t const* data) { + assert((addr.type == iss::address_type::PHYSICAL || is_debug(addr.access)) && "Only physical addresses are expected in pmp"); + if(likely(addr.space == arch::traits::MEM) && !pmp_check(addr.access, addr.val, length) && !is_debug(addr.access)) { hart_if.fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); + if(is_debug(addr.access)) + throw trap_access(0, addr.val); hart_if.reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 1 return iss::Err; } - return down_stream_mem.wr_mem(access, addr, length, data); + return down_stream_mem.wr_mem(addr, length, data); } iss::status read_plain(unsigned addr, reg_t& val) { @@ -156,11 +158,11 @@ template struct pmp : public memory_elem { bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); protected: - arch::priv_if hart_if; + arch::priv_if hart_if; memory_if down_stream_mem; }; -template bool pmp::pmp_check(const access_type type, const uint64_t addr, const unsigned len) { +template bool pmp::pmp_check(const access_type type, const uint64_t addr, const unsigned len) { constexpr auto PMP_SHIFT = 2U; constexpr auto PMP_R = 0x1U; constexpr auto PMP_W = 0x2U; diff --git a/src/iss/semihosting/semihosting.cpp b/src/iss/semihosting/semihosting.cpp index 21fe0c4..0e4d63b 100644 --- a/src/iss/semihosting/semihosting.cpp +++ b/src/iss/semihosting/semihosting.cpp @@ -44,7 +44,7 @@ const char* SYS_OPEN_MODES_STRS[] = {"r", "rb", "r+", "r+b", "w", "wb", "w+", "w template T sh_read_field(iss::arch_if* arch_if_ptr, T addr, int len = 4) { uint8_t bytes[4]; - auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr, 4, &bytes[0]); + auto res = arch_if_ptr->read({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, addr}, 4, &bytes[0]); // auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); if(res != iss::Ok) { @@ -199,7 +199,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc } buffer.resize(num_read); for(int i = 0; i < num_read; i++) { - auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr + i, 1, &buffer[i]); + auto res = arch_if_ptr->write({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, addr + i}, 1, &buffer[i]); if(res != iss::Ok) return; } @@ -277,7 +277,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc for(int i = 0; i < buffer_len; i++) { uint8_t character = filename[i]; - auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, (*parameter) + i, 1, &character); + auto res = arch_if_ptr->write({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, (*parameter) + i}, 1, &character); if(res != iss::Ok) return; } @@ -295,7 +295,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc } case semihosting_syscalls::SYS_WRITEC: { uint8_t character; - auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); + auto res = arch_if_ptr->read({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, *parameter}, 1, &character); if(res != iss::Ok) return; putchar(character); @@ -304,7 +304,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc case semihosting_syscalls::SYS_WRITE0: { uint8_t character; while(1) { - auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); + auto res = arch_if_ptr->read({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, *parameter}, 1, &character); if(res != iss::Ok) return; if(character == 0) diff --git a/src/main.cpp b/src/main.cpp index ca6a09e..2f042ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -102,16 +102,19 @@ int main(int argc, char* argv[]) { LOGGER(DEFAULT)::print_time() = false; LOGGER(connection)::print_time() = false; LOGGER(dbt_rise_iss)::print_time() = false; + LOGGER(disass)::print_time() = false; auto l = logging::as_log_level(clim["verbose"].as()); - LOGGER(DEFAULT)::reporting_level() = l; - LOGGER(connection)::reporting_level() = l; - LOGGER(dbt_rise_iss)::reporting_level() = l; + LOGGER(DEFAULT)::set_reporting_level(l); + LOGGER(connection)::set_reporting_level(l); + LOGGER(dbt_rise_iss)::set_reporting_level(l); + LOGGER(disass)::set_reporting_level(l); if(clim.count("logfile")) { // configure the connection logger auto f = fopen(clim["logfile"].as().c_str(), "w"); LOG_OUTPUT(DEFAULT)::stream() = f; LOG_OUTPUT(connection)::stream() = f; LOG_OUTPUT(dbt_rise_iss)::stream() = f; + LOG_OUTPUT(disass)::stream() = f; } std::vector plugin_list; @@ -207,7 +210,6 @@ int main(int argc, char* argv[]) { } if(clim.count("disass")) { vm->setDisassEnabled(true); - LOGGER(disass)::reporting_level() = logging::INFO; LOGGER(disass)::print_time() = false; auto file_name = clim["disass"].as(); if(file_name.length() > 0) { @@ -273,10 +275,10 @@ int main(int argc, char* argv[]) { LOG(ERR) << "Error opening file " << filename << std::endl; return 1; } - LOGGER(DEFAULT)::reporting_level() = logging::ERR; + LOGGER(DEFAULT)::set_reporting_level(logging::ERR); for(auto addr = start_addr; addr < end_addr; addr += data.size()) { - vm->get_arch()->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0 /*MEM*/, addr, data.size(), - data.data()); // FIXME: get space from iss::arch::traits::mem_type_e::MEM + vm->get_arch()->read({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0 /*iss::arch::traits::MEM*/, addr}, + data.size(), data.data()); // TODO : obey Target endianess uint32_t to_print = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; diff --git a/src/sysc/core2sc_adapter.h b/src/sysc/core2sc_adapter.h index 368a5ac..3118495 100644 --- a/src/sysc/core2sc_adapter.h +++ b/src/sysc/core2sc_adapter.h @@ -35,15 +35,21 @@ #ifndef _SYSC_CORE2SC_ADAPTER_H_ #define _SYSC_CORE2SC_ADAPTER_H_ -#include "core_complex.h" #include "sc2core_if.h" +#include "util/delegate.h" +#include "util/logging.h" #include #include #include #include #include +#include #include +#include +#include +#include #include + namespace sysc { template class core2sc_adapter : public PLAT, public sc2core_if { public: @@ -51,6 +57,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if using core = typename PLAT::core; using reg_t = typename PLAT::reg_t; using phys_addr_t = typename PLAT::phys_addr_t; + using mutex_t = std::shared_mutex; core2sc_adapter(sysc::riscv::core_complex_if* owner) : owner(owner) { this->csr_rd_cb[iss::arch::time] = MK_CSR_RD_CB(read_time); @@ -66,10 +73,37 @@ template class core2sc_adapter : public PLAT, public sc2core_if this->local_irq = util::delegate::from(this); this->register_csr_rd = util::delegate::from(this); this->register_csr_wr = util::delegate::from(this); + + disass_delegate.log = util::delegate(*this, &core2sc_adapter::disass); + disass_delegate.level = logging::log_level::INFO; + this->disasslogger.set_logger(disass_delegate); + log_delegate.log = util::delegate(*this, &core2sc_adapter::log); + log_delegate.level = static_cast(scc::get_logging_level()); + this->isslogger.set_logger(log_delegate); + } + + void setup_mt() override { + this->set_hartid = util::delegate::from(this); + this->set_irq_count = util::delegate::from(this); + this->get_mode = util::delegate::from(this); + this->get_state = util::delegate::from(this); + this->get_interrupt_execution = util::delegate::from(this); + this->set_interrupt_execution = util::delegate::from(this); + this->local_irq = util::delegate::from(this); + this->register_csr_rd = util::delegate::from(this); + this->register_csr_wr = util::delegate::from(this); } virtual ~core2sc_adapter() {} + void enable_disass(bool enable) override { + this->disasslogger.set_log_level(enable ? logging::log_level::DEBUG : logging::log_level::INFO); + } + + void register_unknown_instr_handler(util::delegate handler) override { + PLAT::unknown_instr_cb = handler; + }; + void notify_phase(iss::arch_if::exec_phase p) { if(p == iss::arch_if::ISTART && !first) { auto cycle_incr = owner->get_last_bus_cycles(); @@ -82,15 +116,53 @@ template class core2sc_adapter : public PLAT, public sc2core_if iss::sync_type needed_sync() const { return iss::PRE_SYNC; } - void disass_output(uint64_t pc, const std::string instr) { - static constexpr std::array lvl = {{'U', 'S', 'H', 'M'}}; - if(!owner->disass_output(pc, instr)) { - std::stringstream s; - s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2) - << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount + this->cycle_offset << "]"; - SCCDEBUG(owner->hier_name()) << "disass: " << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc - << "\t\t" << std::setw(40) << std::setfill(' ') << std::left << instr << s.str(); + void log(logging::log_level lvl, std::string const& msg_type, std::string const& msg, unsigned line, char const* file) { + switch(lvl) { + case logging::log_level::FATAL: + ::scc ::ScLogger<::sc_core ::SC_FATAL>(file, line, sc_core ::SC_MEDIUM).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + case logging::log_level::ERR: + ::scc ::ScLogger<::sc_core ::SC_ERROR>(file, line, sc_core ::SC_MEDIUM).type(owner->hier_name()).get() << msg; + break; + case logging::log_level::WARN: + if(::scc ::get_log_verbosity(msg_type) >= sc_core ::SC_LOW) + ::scc ::ScLogger<::sc_core ::SC_WARNING>(file, line, sc_core ::SC_MEDIUM).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + case logging::log_level::INFO: + if(::scc ::get_log_verbosity(msg_type) >= sc_core ::SC_MEDIUM) + ::scc ::ScLogger<::sc_core ::SC_INFO>(file, line, sc_core ::SC_MEDIUM).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + case logging::log_level::DEBUG: + if(::scc ::get_log_verbosity(msg_type) >= sc_core ::SC_HIGH) + ::scc ::ScLogger<::sc_core ::SC_INFO>(file, line, sc_core ::SC_HIGH).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + case logging::log_level::TRACE: + if(::scc ::get_log_verbosity(msg_type) >= sc_core ::SC_FULL) + ::scc ::ScLogger<::sc_core ::SC_INFO>(file, line, sc_core ::SC_FULL).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + case logging::log_level::TRACEALL: + if(::scc ::get_log_verbosity(msg_type) >= sc_core ::SC_DEBUG) + ::scc ::ScLogger<::sc_core ::SC_INFO>(file, line, sc_core ::SC_DEBUG).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + break; + default: + break; } + } + + void disass(logging::log_level lvl, std::string const& msg_type, std::string const& msg, unsigned line, char const* file) { + ::scc ::ScLogger<::sc_core ::SC_INFO>(file, line, sc_core ::SC_HIGH).type(owner->hier_name()).get() + << "[" << msg_type << "] " << msg; + } + + void disass_output(uint64_t pc, std::string const& instr) { + owner->disass_output(pc, instr); + PLAT::disass_output(pc, instr); }; iss::mem::memory_if get_mem_if() { @@ -98,18 +170,18 @@ template class core2sc_adapter : public PLAT, public sc2core_if .wr_mem{util::delegate::from(this)}}; } - iss::status read_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t* data) { - if(access && iss::access_type::DEBUG) + iss::status read_mem(const iss::addr_t& addr, unsigned length, uint8_t* data) { + if(iss::is_debug(addr.access)) return owner->read_mem_dbg(addr, length, data) ? iss::Ok : iss::Err; else { - return owner->read_mem(addr, length, data, is_fetch(access)) ? iss::Ok : iss::Err; + return owner->read_mem(addr, length, data) ? iss::Ok : iss::Err; } } - iss::status write_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t const* data) { - if(access && iss::access_type::DEBUG) + iss::status write_mem(const iss::addr_t& addr, unsigned length, uint8_t const* data) { + if(iss::is_debug(addr.access)) return owner->write_mem_dbg(addr, length, data) ? iss::Ok : iss::Err; - if(addr == this->tohost) { + if(addr.val == this->tohost) { reg_t cur_data = *reinterpret_cast(data); // Extract Device (bits 63:56) uint8_t device = sizeof(reg_t) == 4 ? 0 : (cur_data >> 56) & 0xFF; @@ -131,7 +203,8 @@ template class core2sc_adapter : public PLAT, public sc2core_if } if(device == 0 && command == 0) { std::array loaded_payload; - auto res = owner->read_mem(payload_addr, 8 * sizeof(uint64_t), reinterpret_cast(loaded_payload.data()), false) + auto res = owner->read_mem({addr.type, addr.access, addr.space, payload_addr}, 8 * sizeof(uint64_t), + reinterpret_cast(loaded_payload.data())) ? iss::Ok : iss::Err; if(res == iss::Err) { @@ -171,41 +244,56 @@ template class core2sc_adapter : public PLAT, public sc2core_if void wait_until(uint64_t flags) { SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt"; PLAT::wait_until(flags); - while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { - sc_core::wait(wfi_evt); - } + std::function f = [this]() { + while((this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { + sc_core::wait(this->wfi_evt); + } + SCCINFO(this->owner->hier_name()) << "Got WFI event"; + }; + owner->exec_on_sysc(f); } private: void _set_mhartid(unsigned id) { PLAT::set_mhartid(id); } + void _set_mhartid_mt(unsigned id) { + std::unique_lock lock(sync_mtx); + PLAT::set_mhartid(id); + } void _set_irq_num(unsigned num) { PLAT::set_irq_num(num); } + void _set_irq_num_mt(unsigned num) { + std::unique_lock lock(sync_mtx); + PLAT::set_irq_num(num); + } uint32_t _get_mode() { return this->reg.PRIV; } + uint32_t _get_mode_mt() { + std::shared_lock lock(sync_mtx); + return this->reg.PRIV; + } void _set_interrupt_execution(bool v) { this->interrupt_sim = v ? 1 : 0; } + void _set_interrupt_execution_mt(bool v) { + std::unique_lock lock(sync_mtx); + this->interrupt_sim = v ? 1 : 0; + } bool _get_interrupt_execution() { return this->interrupt_sim; } + bool _get_interrupt_execution_mt() { + std::shared_lock lock(sync_mtx); + return this->interrupt_sim; + } uint64_t _get_state() { return this->state.mstatus.backing.val; } + uint64_t _get_state_mt() { + std::shared_lock lock(sync_mtx); + return this->state.mstatus.backing.val; + } void _local_irq(short id, bool value) { reg_t mask = 0; - switch(id) { - case 3: // SW - mask = 1 << 3; - break; - case 7: // timer - mask = 1 << 7; - break; - case 11: // external - mask = 1 << 11; - break; - default: - if(id > 15) - mask = 1 << id; - break; - } + assert(id < 32 && "CLINT cannot handle more than 32 irq"); + mask = 1 << id; if(value) { this->csr[iss::arch::mip] |= mask; wfi_evt.notify(); @@ -216,7 +304,13 @@ template class core2sc_adapter : public PLAT, public sc2core_if SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; } + void _local_irq_mt(short id, bool value) { + std::unique_lock lock(sync_mtx); + _local_irq(id, value); + } + void _register_csr_rd(unsigned addr, rd_csr_f cb) { + // we need to remap the callback as the cores expects reg_t size datat std::function lambda = [cb](unsigned addr, reg_t& r) -> iss::status { uint64_t temp = r; auto ret = cb(addr, temp); @@ -225,15 +319,28 @@ template class core2sc_adapter : public PLAT, public sc2core_if }; this->register_csr(addr, lambda); } + void _register_csr_rd_mt(unsigned addr, rd_csr_f cb) { + std::unique_lock lock(sync_mtx); + _register_csr_rd(addr, cb); + } + void _register_csr_wr(unsigned addr, wr_csr_f cb) { + // we need to remap the callback as the cores expects reg_t size datat std::function lambda = [cb](unsigned addr, reg_t r) -> iss::status { return cb(addr, r); }; this->register_csr(addr, lambda); } + void _register_csr_wr_mt(unsigned addr, wr_csr_f cb) { + std::unique_lock lock(sync_mtx); + _register_csr_wr(addr, cb); + } sysc::riscv::core_complex_if* const owner{nullptr}; + util::LoggerDelegate log_delegate; + util::LoggerDelegate disass_delegate; sc_core::sc_event wfi_evt; unsigned to_host_wr_cnt = 0; bool first{true}; + mutex_t sync_mtx; }; } // namespace sysc #endif /* _SYSC_CORE2SC_ADAPTER_H_ */ diff --git a/src/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index 728048e..3b48794 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -39,8 +39,12 @@ #include #include #include "iss_factory.h" +#include "sysc/memspace_extension.h" +#include "tlm/scc/tlm_id.h" +#include "util/range_lut.h" #include #include +#include #include #ifndef WIN32 #include @@ -51,15 +55,9 @@ #include #include #include - +#include // clang-format on -#define STR(X) #X -#define CREATE_CORE(CN) \ - if(type == STR(CN)) { \ - std::tie(cpu, vm) = create_core(backend, gdb_port, hart_id); \ - } else - #ifdef HAS_SCV #include #else @@ -91,9 +89,9 @@ iss::debugger::encoder_decoder encdec; std::array lvl = {{'U', 'S', 'H', 'M'}}; } // namespace -template -int core_complex::cmd_sysc(int argc, char* argv[], debugger::out_func of, debugger::data_func df, - debugger::target_adapter_if* tgt_adapter) { +template +int core_complex::cmd_sysc(int argc, char* argv[], debugger::out_func of, debugger::data_func df, + debugger::target_adapter_if* tgt_adapter) { if(argc > 1) { if(strcasecmp(argv[1], "print_time") == 0) { std::string t = sc_time_stamp().to_string(); @@ -122,17 +120,15 @@ int core_complex::cmd_sysc(int argc, char* argv[], debugger::out_func return Err; } -template void core_complex::reset(uint64_t addr) { vm->reset(addr); } -template inline void core_complex::start(bool dump) { - vm->start(std::numeric_limits::max(), dump); -} -template inline std::pair core_complex::load_file(std::string const& name) { +template void core_complex::reset(uint64_t addr) { vm->reset(addr); } +template +inline std::pair core_complex::load_file(std::string const& name) { iss::arch_if* cc = vm->get_arch(); return cc->load_file(name); }; -template -void core_complex::create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id) { +template +void core_complex::create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id) { auto& f = sysc::iss_factory::instance(); if(type.size() == 0 || type == "?") { std::unordered_map> core_by_backend; @@ -183,17 +179,15 @@ void core_complex::create_cpu(std::string const& type, std::string con } #ifndef CWR_SYSTEMC -template -core_complex::core_complex(sc_module_name const& name) -: sc_module(name) -, fetch_lut(tlm_dmi_ext()) -, read_lut(tlm_dmi_ext()) -, write_lut(tlm_dmi_ext()) { +template +core_complex::core_complex(sc_module_name const& name) +: sc_module(name) { init(); } #endif -template void core_complex::init() { +template void core_complex::init() { + core_complex_if::exec_on_sysc = util::delegate&)>::from>(this); ibus.register_invalidate_direct_mem_ptr([this](uint64_t start, uint64_t end) -> void { auto lut_entry = fetch_lut.getEntry(start); if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { @@ -201,50 +195,35 @@ template void core_complex::init() { } }); dbus.register_invalidate_direct_mem_ptr([this](uint64_t start, uint64_t end) -> void { - auto lut_entry = read_lut.getEntry(start); - if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { - read_lut.removeEntry(lut_entry); + for(auto& read_lut : dmi_read_luts) { + auto lut_entry = read_lut.getEntry(start); + if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { + read_lut.removeEntry(lut_entry); + } } - lut_entry = write_lut.getEntry(start); - if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { - write_lut.removeEntry(lut_entry); + for(auto& write_lut : dmi_write_luts) { + auto lut_entry = write_lut.getEntry(start); + if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { + write_lut.removeEntry(lut_entry); + } } }); - SC_HAS_PROCESS(core_complex); // NOLINT + SC_HAS_PROCESS(this_class); // NOLINT SC_THREAD(run); SC_METHOD(rst_cb); sensitive << rst_i; #ifdef USE_TLM_SIGNAL - sw_irq_i.register_nb_transport([this](tlm::scc::tlm_signal_gp& gp, tlm::tlm_phase& p, sc_core::sc_time& t) { - cpu->local_irq(3, gp.get_value()); - return tlm::TLM_COMPLETED; - }); - timer_irq_i.register_nb_transport([this](tlm::scc::tlm_signal_gp& gp, tlm::tlm_phase& p, sc_core::sc_time& t) { - cpu->local_irq(7, gp.get_value()); - return tlm::TLM_COMPLETED; - }); - ext_irq_i.register_nb_transport([this](tlm::scc::tlm_signal_gp& gp, tlm::tlm_phase& p, sc_core::sc_time& t) { - cpu->local_irq(11, gp.get_value()); - return tlm::TLM_COMPLETED; - }); - for(auto i = 0U; i < local_irq_i.size(); ++i) - local_irq_i[i].register_nb_transport([this, i](tlm::scc::tlm_signal_gp& gp, tlm::tlm_phase& p, sc_core::sc_time& t) { - cpu->local_irq(16 + i, gp.get_value()); + for(auto i = 0U; i < clint_irq_i.size(); ++i) + clint_irq_i[i].register_nb_transport([this, i](tlm::scc::tlm_signal_gp& gp, tlm::tlm_phase& p, sc_core::sc_time& t) { + core->local_irq(i, gp.get_value()); return tlm::TLM_COMPLETED; }); #else - SC_METHOD(sw_irq_cb); - sensitive << sw_irq_i; - SC_METHOD(timer_irq_cb); - sensitive << timer_irq_i; - SC_METHOD(ext_irq_cb); - sensitive << ext_irq_i; - SC_METHOD(local_irq_cb); - for(auto pin : local_irq_i) - sensitive << pin; + SC_METHOD(clint_irq_cb); + dont_initialize(); + sensitive << clint_irq_i; #endif - trc.m_db = scv_tr_db::get_default_db(); SC_METHOD(forward); #ifndef CWR_SYSTEMC @@ -257,14 +236,20 @@ template void core_complex::init() { #endif } -template core_complex::~core_complex() { +template core_complex::~core_complex() { for(auto* p : plugin_list) delete p; + if(post_run_stats.get_value()) { + auto instr_if = vm->get_arch()->get_instrumentation_if(); + auto instrs = instr_if->get_instr_count(); + auto cycles = instr_if->get_total_cycles(); + SCCINFO(SCMOD) << "Ran " << instrs << " instructions in " << cycles << " cycles"; + } } -template void core_complex::trace(sc_trace_file* trf) const {} +template void core_complex::trace(sc_trace_file* trf) const {} -template void core_complex::before_end_of_elaboration() { +template void core_complex::before_end_of_elaboration() { auto& type = GET_PROP_VALUE(core_type); SCCDEBUG(SCMOD) << "instantiating core " << type << " with " << GET_PROP_VALUE(backend) << " backend"; // cpu = scc::make_unique(this); @@ -277,10 +262,11 @@ template void core_complex::before_end_of_elab } #endif sc_assert(vm); + auto instr_trace = GET_PROP_VALUE(enable_instr_trace) ? trc.init(this->name()) : false; auto disass = GET_PROP_VALUE(enable_disass); - if(disass && trc.m_db) - SCCINFO(SCMOD) << "Disasssembly will only be in transaction trace database!"; - vm->setDisassEnabled(disass || trc.m_db != nullptr); + if(disass) + core->enable_disass(true); + vm->setDisassEnabled(disass || instr_trace); if(GET_PROP_VALUE(plugins).length()) { auto p = util::split(GET_PROP_VALUE(plugins), ';'); for(std::string const& opt_val : p) { @@ -315,8 +301,7 @@ template void core_complex::before_end_of_elab } } -template void core_complex::start_of_simulation() { - // quantum_keeper.reset(); +template void core_complex::start_of_simulation() { if(GET_PROP_VALUE(elf_file).size() > 0) { auto file_names = util::split(GET_PROP_VALUE(elf_file), ','); for(auto& s : file_names) { @@ -334,28 +319,13 @@ template void core_complex::start_of_simulatio } } } - if(trc.m_db != nullptr && trc.stream_handle == nullptr) { - string basename(this->name()); - trc.stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", trc.m_db); - trc.instr_tr_handle = new scv_tr_generator<>("execute", *trc.stream_handle); - } } -template bool core_complex::disass_output(uint64_t pc, const std::string instr_str) { - if(trc.m_db == nullptr) - return false; - if(trc.tr_handle.is_active()) - trc.tr_handle.end_transaction(); - trc.tr_handle = trc.instr_tr_handle->begin_transaction(); - trc.tr_handle.record_attribute("PC", pc); - trc.tr_handle.record_attribute("INSTR", instr_str); - trc.tr_handle.record_attribute("MODE", lvl[core->get_mode()]); - trc.tr_handle.record_attribute("MSTATUS", core->get_state()); - trc.tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000); - return true; +template void core_complex::disass_output(uint64_t pc, std::string const& instr_str) { + trc.disass_output(pc, instr_str, lvl[core->get_mode()], core->get_state()); } -template void core_complex::forward() { +template void core_complex::forward() { #ifndef CWR_SYSTEMC set_clock_period(clk_i.read()); #else @@ -364,34 +334,29 @@ template void core_complex::forward() { #endif } -template void core_complex::set_clock_period(sc_core::sc_time period) { +template void core_complex::set_clock_period(sc_core::sc_time period) { curr_clk = period; if(period == SC_ZERO_TIME) core->set_interrupt_execution(true); } -template void core_complex::rst_cb() { +template void core_complex::rst_cb() { if(rst_i.read()) core->set_interrupt_execution(true); } #ifndef USE_TLM_SIGNAL -template void core_complex::sw_irq_cb() { core->local_irq(3, sw_irq_i.read()); } - -template void core_complex::timer_irq_cb() { core->local_irq(7, timer_irq_i.read()); } - -template void core_complex::ext_irq_cb() { core->local_irq(11, ext_irq_i.read()); } - -template void core_complex::local_irq_cb() { - for(auto i = 0U; i < local_irq_i.size(); ++i) { - if(local_irq_i[i].event()) { - core->local_irq(16 + i, local_irq_i[i].read()); +template void core_complex::clint_irq_cb() { + for(auto i = 0U; i < clint_irq_i.size(); ++i) { + if(clint_irq_i[i].event()) { + core->local_irq(i, clint_irq_i[i].read()); } } } #endif -template void core_complex::run() { +template void core_complex::run() { + reset(GET_PROP_VALUE(reset_address)); wait(SC_ZERO_TIME); // separate from elaboration phase do { wait(SC_ZERO_TIME); @@ -402,42 +367,58 @@ template void core_complex::run() { while(curr_clk.read() == SC_ZERO_TIME) { wait(curr_clk.value_changed_event()); } - quantum_keeper.reset(); + quantum_keeper.reset(sc_core::sc_time_stamp()); core->set_interrupt_execution(false); - start(dump_ir); + run_iss(); } while(!core->get_interrupt_execution()); - sc_stop(); + if(finish_evt_inuse) + finish_evt.notify(); + else { + if(sc_core::sc_get_simulator_status() != sc_core::SC_SIM_USER_STOP) // stop simulation + sc_stop(); + } } -template bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) { - auto& dmi_lut = is_fetch ? fetch_lut : read_lut; - auto lut_entry = dmi_lut.getEntry(addr); - if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && (addr + length) <= (lut_entry.get_end_address() + 1)) { - auto offset = addr - lut_entry.get_start_address(); +template +bool core_complex::read_mem(const addr_t& addr, unsigned length, uint8_t* const data) { + // basically checking for mem_type_e in CORENAME.h + bool is_fetch = addr.space == std::numeric_limits::max() ? true : false; + auto& dmi_lut = is_fetch ? fetch_lut : get_read_lut(addr.space); + auto lut_entry = dmi_lut.getEntry(addr.val); + if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && (addr.val + length) <= (lut_entry.get_end_address() + 1)) { + auto offset = addr.val - lut_entry.get_start_address(); std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data); if(is_fetch) ibus_inc += lut_entry.get_read_latency() / curr_clk; else dbus_inc += lut_entry.get_read_latency() / curr_clk; +#ifndef NDEBUG + SCCTRACE(this->name()) << "[local offset: +" << quantum_keeper.get_local_time() << "]: finish dmi_read_mem(0x" << std::hex + << addr.val << ") : 0x" + << (length == 4 ? *(uint32_t*)data + : length == 2 ? *(uint16_t*)data + : (unsigned)*data); +#endif return true; } else { - auto& sckt = is_fetch ? ibus : dbus; tlm::tlm_generic_payload gp; gp.set_command(tlm::TLM_READ_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); gp.set_data_ptr(data); gp.set_data_length(length); gp.set_streaming_width(length); sc_time delay = quantum_keeper.get_local_time(); - if(trc.m_db != nullptr && trc.tr_handle.is_valid()) { - if(is_fetch && trc.tr_handle.is_active()) { - trc.tr_handle.end_transaction(); - } - auto preExt = new tlm::scc::scv::tlm_recording_extension(trc.tr_handle, this); - gp.set_extension(preExt); - } + sysc::memspace::tlm_memspace_extension<> mem_spc(static_cast(addr.space)); + if(!is_fetch) + gp.set_extension(&mem_spc); + tlm::scc::initiator_id_extension id_ext{mhartid.get_value()}; + gp.set_extension(&id_ext); + DEFER { + gp.set_extension(nullptr); + gp.set_extension>(nullptr); + }; auto pre_delay = delay; - sckt->b_transport(gp, delay); + exec_b_transport(gp, delay, is_fetch); if(pre_delay > delay) { quantum_keeper.reset(); } else { @@ -447,19 +428,18 @@ template bool core_complex::read_mem(uint64_t else dbus_inc += incr; } - SCCTRACE(this->name()) << "[local time: " << delay << "]: finish read_mem(0x" << std::hex << addr << ") : 0x" + SCCTRACE(this->name()) << "[local offset: +" << delay << "]: finish read_mem(0x" << std::hex << addr.val << ") : 0x" << (length == 4 ? *(uint32_t*)data : length == 2 ? *(uint16_t*)data : (unsigned)*data); - if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) { + if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) return false; - } if(gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) { gp.set_command(tlm::TLM_READ_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); tlm_dmi_ext dmi_data; - if(sckt->get_direct_mem_ptr(gp, dmi_data)) { - if(dmi_data.is_read_allowed() && (addr + length - 1) <= dmi_data.get_end_address()) + if(exec_get_direct_mem_ptr(gp, dmi_data)) { + if(dmi_data.is_read_allowed() && (addr.val + length - 1) <= dmi_data.get_end_address()) dmi_lut.addEntry(dmi_data, dmi_data.get_start_address(), dmi_data.get_end_address() - dmi_data.get_start_address() + 1); } } @@ -467,79 +447,113 @@ template bool core_complex::read_mem(uint64_t } } -template bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* const data) { - auto lut_entry = write_lut.getEntry(addr); - if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && (addr + length) <= (lut_entry.get_end_address() + 1)) { - auto offset = addr - lut_entry.get_start_address(); +template +bool core_complex::write_mem(const addr_t& addr, unsigned length, const uint8_t* const data) { + auto lut_entry = get_write_lut(addr.space).getEntry(addr.val); + if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && (addr.val + length) <= (lut_entry.get_end_address() + 1)) { + auto offset = addr.val - lut_entry.get_start_address(); std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset); dbus_inc += lut_entry.get_write_latency() / curr_clk; +#ifndef NDEBUG + SCCTRACE(this->name()) << "[local offset: +" << quantum_keeper.get_local_time() << "]: finish dmi_write_mem(0x" << std::hex + << addr.val << ") : 0x" + << (length == 4 ? *(uint32_t*)data + : length == 2 ? *(uint16_t*)data + : (unsigned)*data); +#endif return true; } else { write_buf.resize(length); std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity tlm::tlm_generic_payload gp; gp.set_command(tlm::TLM_WRITE_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); gp.set_data_ptr(write_buf.data()); gp.set_data_length(length); gp.set_streaming_width(length); sc_time delay = quantum_keeper.get_local_time(); - if(trc.m_db != nullptr && trc.tr_handle.is_valid()) { - auto preExt = new tlm::scc::scv::tlm_recording_extension(trc.tr_handle, this); - gp.set_extension(preExt); - } + sysc::memspace::tlm_memspace_extension<> mem_spc(static_cast(addr.space)); + gp.set_extension(&mem_spc); + tlm::scc::initiator_id_extension id_ext{mhartid.get_value()}; + gp.set_extension(&id_ext); + DEFER { + gp.set_extension(nullptr); + gp.set_extension>(nullptr); + }; auto pre_delay = delay; - dbus->b_transport(gp, delay); + exec_b_transport(gp, delay); if(pre_delay > delay) quantum_keeper.reset(); else dbus_inc += (delay - quantum_keeper.get_local_time()) / curr_clk; - SCCTRACE() << "[local time: " << delay << "]: finish write_mem(0x" << std::hex << addr << ") : 0x" - << (length == 4 ? *(uint32_t*)data - : length == 2 ? *(uint16_t*)data - : (unsigned)*data); - if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) { + SCCTRACE(this->name()) << "[local offset: +" << delay << "]: finish write_mem(0x" << std::hex << addr.val << ") : 0x" + << (length == 4 ? *(uint32_t*)data + : length == 2 ? *(uint16_t*)data + : (unsigned)*data); + if(gp.get_response_status() != tlm::TLM_OK_RESPONSE) return false; - } if(gp.is_dmi_allowed() && !GET_PROP_VALUE(disable_dmi)) { gp.set_command(tlm::TLM_READ_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); tlm_dmi_ext dmi_data; - if(dbus->get_direct_mem_ptr(gp, dmi_data)) { - if(dmi_data.is_write_allowed() && (addr + length - 1) <= dmi_data.get_end_address()) - write_lut.addEntry(dmi_data, dmi_data.get_start_address(), - dmi_data.get_end_address() - dmi_data.get_start_address() + 1); + if(exec_get_direct_mem_ptr(gp, dmi_data)) { + if(dmi_data.is_write_allowed() && (addr.val + length - 1) <= dmi_data.get_end_address()) + get_write_lut(addr.space) + .addEntry(dmi_data, dmi_data.get_start_address(), dmi_data.get_end_address() - dmi_data.get_start_address() + 1); } } return true; } } -template bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) { +template +bool core_complex::read_mem_dbg(const addr_t& addr, unsigned length, uint8_t* const data) { tlm::tlm_generic_payload gp; gp.set_command(tlm::TLM_READ_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); gp.set_data_ptr(data); gp.set_data_length(length); gp.set_streaming_width(length); + gp.set_extension(new sysc::memspace::tlm_memspace_extension<>(static_cast(addr.space))); return dbus->transport_dbg(gp) == length; } -template bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) { +template +bool core_complex::write_mem_dbg(const addr_t& addr, unsigned length, const uint8_t* const data) { write_buf.resize(length); std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity tlm::tlm_generic_payload gp; gp.set_command(tlm::TLM_WRITE_COMMAND); - gp.set_address(addr); + gp.set_address(addr.val); gp.set_data_ptr(write_buf.data()); gp.set_data_length(length); gp.set_streaming_width(length); + gp.set_extension(new sysc::memspace::tlm_memspace_extension<>(static_cast(addr.space))); return dbus->transport_dbg(gp) == length; } +template util::range_lut& core_complex::get_read_lut(unsigned space) { + return get_lut(dmi_read_luts, space); +}; +template util::range_lut& core_complex::get_write_lut(unsigned space) { + return get_lut(dmi_write_luts, space); +}; +template +util::range_lut& core_complex::get_lut(lut_vec_t& luts, unsigned space) { + if(space >= luts.size()) { + luts.reserve(space + 1); + // cannot use resize as assignment and move assignment operator are not supported by range_luts with tlm_dmi_ext as defaults + while(space >= luts.size()) + luts.emplace_back(tlm_dmi_ext()); + } + return luts[space]; +}; template class core_complex; template class core_complex<32>; template class core_complex<64>; +template class core_complex; +template class core_complex<32, tlm::scc::quantumkeeper_mt>; +template class core_complex<64, tlm::scc::quantumkeeper_mt>; } // namespace riscv } /* namespace sysc */ diff --git a/src/sysc/core_complex.h b/src/sysc/core_complex.h index ac4f01b..2c4c097 100644 --- a/src/sysc/core_complex.h +++ b/src/sysc/core_complex.h @@ -34,6 +34,7 @@ #define _SYSC_CORE_COMPLEX_H_ #include "core_complex_if.h" +#include "instr_recorder.h" #include "sc2core_if.h" #include #include @@ -42,8 +43,11 @@ #include #include #include +#include #include +#include #include +#include #ifdef CWR_SYSTEMC #include #else @@ -80,21 +84,20 @@ using irq_signal_t = tlm::scc::tlm_signal_bool_opt_in; using irq_signal_t = sc_core::sc_in; #endif -template class core_complex : public sc_core::sc_module, public scc::traceable, public core_complex_if { +enum { SW_IRQ = 3, TIMER_IRQ = 7, EXT_IRQ = 11 }; + +template +class core_complex : public sc_core::sc_module, public scc::traceable, public core_complex_if { public: + using this_class = core_complex; + tlm::scc::initiator_mixin> ibus{"ibus"}; tlm::scc::initiator_mixin> dbus{"dbus"}; sc_core::sc_in rst_i{"rst_i"}; - irq_signal_t ext_irq_i{"ext_irq_i"}; - - irq_signal_t timer_irq_i{"timer_irq_i"}; - - irq_signal_t sw_irq_i{"sw_irq_i"}; - - sc_core::sc_vector local_irq_i{"local_irq_i", 16}; + sc_core::sc_vector clint_irq_i{"clint_irq_i", 32}; #ifndef CWR_SYSTEMC sc_core::sc_in clk_i{"clk_i"}; @@ -103,6 +106,8 @@ template class core_complex : public sc_core:: cci::cci_param enable_disass{"enable_disass", false}; + cci::cci_param enable_instr_trace{"enable_instr_trace", true}; + cci::cci_param disable_dmi{"disable_dmi", false}; cci::cci_param reset_address{"reset_address", 0ULL}; @@ -121,6 +126,8 @@ template class core_complex : public sc_core:: cci::cci_param plugins{"plugins", ""}; + cci::cci_param post_run_stats{"post_run_stats", false}; + core_complex(sc_core::sc_module_name const& name); #else @@ -146,6 +153,8 @@ template class core_complex : public sc_core:: scml_property plugins{"plugins", ""}; + scml_property post_run_stats{"post_run_stats", false}; + core_complex(sc_core::sc_module_name const& name) : sc_module(name) , local_irq_i{"local_irq_i", 16} @@ -176,25 +185,21 @@ template class core_complex : public sc_core:: void sync(uint64_t cycle) override { auto core_inc = curr_clk * (cycle - last_sync_cycle); - quantum_keeper.inc(core_inc); - if(quantum_keeper.need_sync()) { - wait(quantum_keeper.get_local_time()); - quantum_keeper.reset(); - } + quantum_keeper.check_and_sync(core_inc); last_sync_cycle = cycle; } - bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) override; + bool read_mem(const iss::addr_t& a, unsigned length, uint8_t* const data) override; - bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) override; + bool write_mem(const iss::addr_t& a, unsigned length, const uint8_t* const data) override; - bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) override; + bool read_mem_dbg(const iss::addr_t& a, unsigned length, uint8_t* const data) override; - bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) override; + bool write_mem_dbg(const iss::addr_t& a, unsigned length, const uint8_t* const data) override; void trace(sc_core::sc_trace_file* trf) const override; - bool disass_output(uint64_t pc, const std::string instr) override; + void disass_output(uint64_t pc, std::string const& instr) override; void set_clock_period(sc_core::sc_time period); @@ -202,48 +207,104 @@ template class core_complex : public sc_core:: void reset(uint64_t addr); - inline void start(bool dump = false); - inline std::pair load_file(std::string const& name); + sc_core::sc_event const& get_finish_event() { + finish_evt_inuse = true; + return finish_evt; + } + protected: void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id); int cmd_sysc(int argc, char* argv[], iss::debugger::out_func, iss::debugger::data_func, iss::debugger::target_adapter_if*); - void before_end_of_elaboration() override; void start_of_simulation() override; void forward(); void run(); void rst_cb(); #ifndef USE_TLM_SIGNAL - void sw_irq_cb(); - void timer_irq_cb(); - void ext_irq_cb(); - void local_irq_cb(); + void clint_irq_cb(); #endif + /////////////////////////////////////////////////////////////////////////////// + // multi-threaded function implementations + /////////////////////////////////////////////////////////////////////////////// + template + typename std::enable_if::value>::type + exec_b_transport(tlm::tlm_generic_payload& gp, sc_core::sc_time& delay, bool is_fetch = false) { + quantum_keeper.execute_on_sysc([this, &gp, &delay, is_fetch]() { + auto& sckt = is_fetch ? ibus : dbus; + gp.set_extension(trc.get_recording_extension(is_fetch)); + sckt->b_transport(gp, delay); + }); + } + template + typename std::enable_if::value, bool>::type + exec_get_direct_mem_ptr(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) { + return dbus->get_direct_mem_ptr(gp, dmi_data); + } + template + typename std::enable_if::value>::type exec_on_sysc(std::function& f) { + quantum_keeper.execute_on_sysc(f); + } + template typename std::enable_if::value>::type run_iss() { + core->setup_mt(); + quantum_keeper.check_and_sync(sc_core::SC_ZERO_TIME); + quantum_keeper.run_thread([this]() { + vm->start(std::numeric_limits::max(), dump_ir); + return quantum_keeper.get_local_absolute_time(); + }); + } + /////////////////////////////////////////////////////////////////////////////// + // single-threaded function implementations + /////////////////////////////////////////////////////////////////////////////// + template + typename std::enable_if::value>::type + exec_b_transport(tlm::tlm_generic_payload& gp, sc_core::sc_time& delay, bool is_fetch = false) { + auto& sckt = is_fetch ? ibus : dbus; + gp.set_extension(trc.get_recording_extension(is_fetch)); + sckt->b_transport(gp, delay); + } + template + typename std::enable_if::value, bool>::type + exec_get_direct_mem_ptr(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) { + auto result = false; + quantum_keeper.execute_on_sysc([this, &gp, &dmi_data, &result]() { result = dbus->get_direct_mem_ptr(gp, dmi_data); }); + return result; + } + template + typename std::enable_if::value>::type exec_on_sysc(std::function& f) { + f(); + } + template typename std::enable_if::value>::type run_iss() { + vm->start(std::numeric_limits::max(), dump_ir); + } + /////////////////////////////////////////////////////////////////////////////// + // + /////////////////////////////////////////////////////////////////////////////// uint64_t last_sync_cycle = 0; - util::range_lut fetch_lut, read_lut, write_lut; - tlm_utils::tlm_quantumkeeper quantum_keeper; + util::range_lut fetch_lut{tlm_dmi_ext()}; + inline util::range_lut& get_read_lut(unsigned space); + inline util::range_lut& get_write_lut(unsigned space); + + QK quantum_keeper; std::vector write_buf; sc_core::sc_signal curr_clk; uint64_t ibus_inc{0}, dbus_inc{0}; std::unique_ptr core; std::unique_ptr vm; iss::debugger::target_adapter_if* tgt_adapter{nullptr}; - - struct { - //! transaction recording database - SCVNS scv_tr_db* m_db{nullptr}; - //! blocking transaction recording stream handle - SCVNS scv_tr_stream* stream_handle{nullptr}; - //! transaction generator handle for blocking transactions - SCVNS scv_tr_generator* instr_tr_handle{nullptr}; - SCVNS scv_tr_handle tr_handle; - } trc; + instr_recorder trc{quantum_keeper}; std::unique_ptr t2t; + sc_core::sc_event finish_evt{"finish_evt"}; + bool finish_evt_inuse{false}; private: void init(); + // we reserve for 8 memory spaces + using lut_vec_t = std::vector>; + lut_vec_t dmi_read_luts{8, util::range_lut(tlm_dmi_ext())}; + lut_vec_t dmi_write_luts{8, util::range_lut(tlm_dmi_ext())}; + util::range_lut& get_lut(lut_vec_t& luts, unsigned space); std::vector plugin_list; }; } // namespace riscv diff --git a/src/sysc/core_complex_if.h b/src/sysc/core_complex_if.h index d96ccaa..5e45a33 100644 --- a/src/sysc/core_complex_if.h +++ b/src/sysc/core_complex_if.h @@ -33,7 +33,9 @@ #ifndef _SYSC_CORE_COMPLEX__IF_H_ #define _SYSC_CORE_COMPLEX__IF_H_ +#include #include +#include namespace sysc { namespace riscv { @@ -41,21 +43,23 @@ struct core_complex_if { virtual ~core_complex_if() = default; - virtual bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) = 0; + virtual bool read_mem(const iss::addr_t& addr, unsigned length, uint8_t* const data) = 0; - virtual bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) = 0; + virtual bool write_mem(const iss::addr_t& addr, unsigned length, const uint8_t* const data) = 0; - virtual bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) = 0; + virtual bool read_mem_dbg(const iss::addr_t& addr, unsigned length, uint8_t* const data) = 0; - virtual bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) = 0; + virtual bool write_mem_dbg(const iss::addr_t& addr, unsigned length, const uint8_t* const data) = 0; - virtual bool disass_output(uint64_t pc, const std::string instr) = 0; + virtual void disass_output(uint64_t pc, std::string const& instr) = 0; virtual unsigned get_last_bus_cycles() = 0; //! Allow quantum keeper handling virtual void sync(uint64_t) = 0; + util::delegate&)> exec_on_sysc; + virtual char const* hier_name() = 0; scc::sc_in_opt mtime_i{"mtime_i"}; diff --git a/src/sysc/instr_recorder.h b/src/sysc/instr_recorder.h new file mode 100644 index 0000000..57f269b --- /dev/null +++ b/src/sysc/instr_recorder.h @@ -0,0 +1,126 @@ +#pragma once + +#include "scv-tr/scv_tr.h" +#include +#include +#include +#ifdef HAS_SCV +#include +#else +#include +#ifndef SCVNS +#define SCVNS ::scv_tr:: +#endif +#endif + +namespace sysc { +namespace riscv { + +struct instr_recorder_b { + bool init(std::string const& basename) { + if(tx_db != nullptr) { + stream_hnd = new SCVNS scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", tx_db); + gen_hndl = new SCVNS scv_tr_generator<>("execute", *stream_hnd); + gen_timed_hndl = new SCVNS scv_tr_generator<>("execute(timed)", *stream_hnd); + return true; + } + return false; + } + instr_recorder_b(SCVNS scv_tr_db* tx_db = SCVNS scv_tr_db::get_default_db()) + : tx_db(tx_db) {} + void record_instr(uint64_t pc, std::string const& instr_str, char mode, uint64_t status, sc_core::sc_time ltime) { + tx_hndl = gen_hndl->begin_transaction(); + tx_hndl.record_attribute("PC", pc); + tx_hndl.record_attribute("INSTR", instr_str); + tx_hndl.record_attribute("MODE", mode); + tx_hndl.record_attribute("MSTATUS", status); + tx_hndl.record_attribute("LTIME_START(ps)", static_cast(ltime / 1_ps)); + tx_hndl.end_transaction(); + if(tx_timed_hndl.is_active()) + gen_timed_hndl->end_transaction(tx_timed_hndl, ltime); + tx_timed_hndl = gen_timed_hndl->begin_transaction(ltime); + tx_timed_hndl.record_attribute("PC", pc); + tx_timed_hndl.record_attribute("INSTR", instr_str); + tx_timed_hndl.record_attribute("MODE", mode); + tx_timed_hndl.record_attribute("MSTATUS", status); + tx_timed_hndl.add_relation("PARENT/CHILD", tx_hndl); + } + + tlm::scc::scv::tlm_recording_extension* get_recording_extension(bool finish_instr) { + if(tx_db != nullptr) { + if(tx_timed_hndl.is_valid()) { + return new tlm::scc::scv::tlm_recording_extension(tx_timed_hndl, this); + } else if(tx_hndl.is_valid()) { + return new tlm::scc::scv::tlm_recording_extension(tx_hndl, this); + } + } + return nullptr; + } + +protected: + //! transaction recording database + SCVNS scv_tr_db* tx_db{nullptr}; + //! blocking transaction recording stream handle + SCVNS scv_tr_stream* stream_hnd{nullptr}; + //! transaction generator handle for blocking transactions + SCVNS scv_tr_generator* gen_hndl{nullptr}; + SCVNS scv_tr_generator* gen_timed_hndl{nullptr}; + SCVNS scv_tr_handle tx_hndl; + SCVNS scv_tr_handle tx_timed_hndl; +}; + +template struct instr_recorder : instr_recorder_b {}; + +template <> struct instr_recorder : instr_recorder_b { + void disass_output(uint64_t pc, std::string const& instr_str, char mode, uint64_t status) { + if(stream_hnd == nullptr) + return; + record_instr(pc, instr_str, mode, status, quantum_keeper.get_local_absolute_time()); + } + instr_recorder(tlm::scc::quantumkeeper& quantum_keeper) + : quantum_keeper(quantum_keeper) {} + +protected: + tlm::scc::quantumkeeper& quantum_keeper; +}; + +template <> struct instr_recorder : instr_recorder_b { + void disass_output(uint64_t pc, std::string const& instr_str, char mode, uint64_t status) { + if(stream_hnd == nullptr) + return; + que.push(instr_record{pc, instr_str, mode, status, quantum_keeper.get_local_absolute_time()}); + } + + void record() { + while(auto r = que.front()) { + record_instr(r->pc, r->instr_str, r->mode, r->status, r->start_time); + que.pop(); + } + } + + struct callback : sc_core::sc_stage_callback_if { + void stage_callback(const sc_core::sc_stage& stage) override { owner->record(); } + callback(instr_recorder* owner) + : owner(owner) {} + instr_recorder* owner; + } stage_cb{this}; + + instr_recorder(tlm::scc::quantumkeeper_mt& quantum_keeper) + : quantum_keeper(quantum_keeper) + , que(8 * 1024) { + sc_core::sc_register_stage_callback(stage_cb, sc_core::SC_PRE_TIMESTEP); + } + +protected: + struct instr_record { + uint64_t pc; + std::string const instr_str; + char mode; + uint64_t status; + sc_core::sc_time start_time; + }; + tlm::scc::quantumkeeper_mt& quantum_keeper; + rigtorp::SPSCQueue que; +}; +} // namespace riscv +} // namespace sysc \ No newline at end of file diff --git a/src/sysc/memspace_dispatcher.h b/src/sysc/memspace_dispatcher.h new file mode 100644 index 0000000..d5b2209 --- /dev/null +++ b/src/sysc/memspace_dispatcher.h @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (C) 2025 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#ifndef _SYSC_MEMSPACE_DISPATCHER_H_ +#define _SYSC_MEMSPACE_DISPATCHER_H_ +#include "scc/report.h" +#include "scc/utilities.h" +#include "tlm/scc/initiator_mixin.h" +#include "tlm/scc/target_mixin.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace sysc { +namespace memspace { +template > +struct memspace_dispatcher : sc_core::sc_module { + using intor_sckt = tlm::scc::initiator_mixin>; + using target_sckt = tlm::scc::target_mixin; + + target_sckt target; + sc_core::sc_vector initiator; + memspace_dispatcher(const sc_core::sc_module_name& nm, size_t slave_cnt = 1) + : sc_module(nm) + , initiator("intor", slave_cnt) { + sc_assert(slave_cnt > 0 && "memspace_dispatcher requires at least a single downstream module"); + target.register_b_transport( + [this](tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) { mapped_intor(trans)->b_transport(trans, delay); }); + target.register_get_direct_mem_ptr([this](tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) { + return mapped_intor(trans, true)->get_direct_mem_ptr(trans, dmi_data); + }); + target.register_transport_dbg([this](tlm::tlm_generic_payload& trans) { return mapped_intor(trans)->transport_dbg(trans); }); + for(size_t i = 0; i < initiator.size(); i++) { + initiator[i].register_invalidate_direct_mem_ptr([this](::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range) { + target->invalidate_direct_mem_ptr(start_range, end_range); + }); + } + }; + template void bind_target(TYPE& socket, size_t port_idx) { initiator[port_idx].bind(socket); }; + void map_space_to_port(MEMSPACE space_id, unsigned port_idx) { + sc_assert(port_idx < initiator.size() && "Targeted port index is higher than registered initiator sockets"); + if(space_mapping.count(space_id)) + SCCDEBUG(SCMOD) << "remapping of space_id " << static_cast(space_id); + space_mapping[space_id] = port_idx; + }; + void set_default_port(unsigned port_idx) { + sc_assert(port_idx < initiator.size() && "Targeted port index is higher than registered initiator sockets"); + default_port = port_idx; + }; + +private: + std::unordered_map space_mapping{}; + size_t default_port = 0; + intor_sckt& mapped_intor(const tlm::tlm_generic_payload& trans, bool dmi = false) { + if(auto* ext = trans.get_extension>()) { + auto it = space_mapping.find(ext->get_space()); + if(it != space_mapping.end()) { +#ifndef NDEBUG + auto prefix = dmi ? "DMI " : ""; + SCCTRACE(SCMOD) << "Sending " << prefix << "transaction to initiator " << it->second; +#endif + return initiator[it->second]; + } + } +#ifndef NDEBUG + auto prefix = dmi ? "DMI " : ""; + SCCTRACE(SCMOD) << "Sending " << prefix << "transaction to default initiator " << default_port; +#endif + return initiator[default_port]; + } +}; +} // namespace memspace +} // namespace sysc + +#endif /*_SYSC_MEMSPACE_DISPATCHER_H_*/ \ No newline at end of file diff --git a/src/iss/arch/rv32imc.cpp b/src/sysc/memspace_extension.h similarity index 58% rename from src/iss/arch/rv32imc.cpp rename to src/sysc/memspace_extension.h index 99aa057..d62218c 100644 --- a/src/iss/arch/rv32imc.cpp +++ b/src/sysc/memspace_extension.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2017 - 2020 MINRES Technologies GmbH + * Copyright (C) 2025 MINRES Technologies GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,41 +30,31 @@ * *******************************************************************************/ -// clang-format off -#include "rv32imc.h" -#include "util/ities.h" -#include -#include -#include -#include - -using namespace iss::arch; - -constexpr std::array iss::arch::traits::reg_names; -constexpr std::array iss::arch::traits::reg_aliases; -constexpr std::array iss::arch::traits::reg_bit_widths; -constexpr std::array iss::arch::traits::reg_byte_offsets; - -rv32imc::rv32imc() = default; - -rv32imc::~rv32imc() = default; - -void rv32imc::reset(uint64_t address) { - auto base_ptr = reinterpret_cast::reg_t*>(get_regs_base_ptr()); - for(size_t i=0; i::NUM_REGS; ++i) - *(base_ptr+i)=0; - reg.PC=address; - reg.NEXT_PC=reg.PC; - reg.PRIV=0x3; - reg.trap_state=0; - reg.icount=0; -} - -uint8_t *rv32imc::get_regs_base_ptr() { - return reinterpret_cast(®); -} - -rv32imc::phys_addr_t rv32imc::virt2phys(const iss::addr_t &addr) { - return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); -} -// clang-format on +#ifndef _SYSC_MEMSPACE_EXTENSION_H_ +#define _SYSC_MEMSPACE_EXTENSION_H_ +#include +#include +#include +#include +namespace sysc { +namespace memspace { +// the same enum as the mem_type_e in CORENAME.h +enum class common : uint32_t { MEM, FENCE, RES, CSR, IMEM = std::numeric_limits::max() }; + +template class tlm_memspace_extension : public tlm::tlm_extension> { +public: + tlm_memspace_extension(MEMSPACE space) + : space(space) {} + + tlm::tlm_extension_base* clone() const { return new tlm_memspace_extension(this->space); } + + void copy_from(tlm::tlm_extension_base const& other) { *this = static_cast(other); } + MEMSPACE get_space() const { return space; } + +private: + MEMSPACE space; +}; +} // namespace memspace +} // namespace sysc + +#endif /*_SYSC_MEMSPACE_EXTENSION_H_*/ \ No newline at end of file diff --git a/src/sysc/register_cores.cpp b/src/sysc/register_cores.cpp index eac7154..6e02119 100644 --- a/src/sysc/register_cores.cpp +++ b/src/sysc/register_cores.cpp @@ -124,15 +124,15 @@ volatile std::array riscv_init = { namespace llvm { using namespace sysc; volatile std::array riscv_init = { - iss_factory::instance().register_creator("rv32imc_m:llvm", + iss_factory::instance().register_creator("rv32imac_m:llvm", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { auto* cpu = new core2sc_adapter>(cc); - return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), - iss_factory::instance().register_creator("rv32imc_mu:llvm", + iss_factory::instance().register_creator("rv32imac_mu:llvm", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { auto* cpu = new core2sc_adapter>(cc); - return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; + return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), iss_factory::instance().register_creator("tgc5c_m:llvm", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { diff --git a/src/sysc/sc2core_if.h b/src/sysc/sc2core_if.h index 7626334..44574ee 100644 --- a/src/sysc/sc2core_if.h +++ b/src/sysc/sc2core_if.h @@ -35,6 +35,7 @@ #ifndef _SYSC_SC2CORE_IF_H_ #define _SYSC_SC2CORE_IF_H_ +#include "iss/arch_if.h" #include #include #include @@ -47,6 +48,9 @@ struct sc2core_if { // this is needed since we want to call the destructor with a pointer-to-base virtual ~sc2core_if() = default; + virtual void setup_mt() = 0; + + virtual void enable_disass(bool enable) = 0; util::delegate set_hartid; util::delegate set_irq_count; util::delegate get_mode; @@ -60,6 +64,7 @@ struct sc2core_if { //! sets a callback for CSR write requests. The callback gets always 64bit data passed no matter what size the actual CSR has using wr_csr_f = std::function; util::delegate register_csr_wr; + virtual void register_unknown_instr_handler(util::delegate) = 0; }; } // namespace sysc #endif /* _SYSC_SC2CORE_IF_H_ */ diff --git a/src/vm/asmjit/vm_rv32gc.cpp b/src/vm/asmjit/vm_rv32gc.cpp index 07f2bdf..fd3c84f 100644 --- a/src/vm/asmjit/vm_rv32gc.cpp +++ b/src/vm/asmjit/vm_rv32gc.cpp @@ -9986,9 +9986,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv32gcv.cpp b/src/vm/asmjit/vm_rv32gcv.cpp index 9a0ad8f..92023c1 100644 --- a/src/vm/asmjit/vm_rv32gcv.cpp +++ b/src/vm/asmjit/vm_rv32gcv.cpp @@ -11850,8 +11850,10 @@ template class vm_impl : public iss::asmjit::vm_base { setArg(call_calculate_new_vl_260, 1, uimm); setArg(call_calculate_new_vl_260, 2, calculate_new_vl_260_arg1); setRet(call_calculate_new_vl_260, 0, ret_val_calculate_new_vl_260); - mov(cc, get_ptr_for(jh, traits::X0+ rd), - load_reg_from_mem(jh, traits::vl)); + if(rd!=0){ + mov(cc, get_ptr_for(jh, traits::X0+ rd), + load_reg_from_mem(jh, traits::vl)); + } auto tmp261 = get_reg_Gp(cc, 32, false); mov(cc, tmp261, gen_ext(cc, 0, 32, false)); write_reg_to_mem(jh, tmp261, traits::vstart); @@ -85391,9 +85393,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv32i.cpp b/src/vm/asmjit/vm_rv32i.cpp index 8841d85..3788601 100644 --- a/src/vm/asmjit/vm_rv32i.cpp +++ b/src/vm/asmjit/vm_rv32i.cpp @@ -2829,9 +2829,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv32imac.cpp b/src/vm/asmjit/vm_rv32imac.cpp index ef5fd9e..11de413 100644 --- a/src/vm/asmjit/vm_rv32imac.cpp +++ b/src/vm/asmjit/vm_rv32imac.cpp @@ -5429,9 +5429,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv64gc.cpp b/src/vm/asmjit/vm_rv64gc.cpp index 153be17..7e74b61 100644 --- a/src/vm/asmjit/vm_rv64gc.cpp +++ b/src/vm/asmjit/vm_rv64gc.cpp @@ -12567,9 +12567,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv64gcv.cpp b/src/vm/asmjit/vm_rv64gcv.cpp index 600f51d..1e7e94c 100644 --- a/src/vm/asmjit/vm_rv64gcv.cpp +++ b/src/vm/asmjit/vm_rv64gcv.cpp @@ -14431,8 +14431,10 @@ template class vm_impl : public iss::asmjit::vm_base { setArg(call_calculate_new_vl_296, 1, uimm); setArg(call_calculate_new_vl_296, 2, calculate_new_vl_296_arg1); setRet(call_calculate_new_vl_296, 0, ret_val_calculate_new_vl_296); - mov(cc, get_ptr_for(jh, traits::X0+ rd), - load_reg_from_mem(jh, traits::vl)); + if(rd!=0){ + mov(cc, get_ptr_for(jh, traits::X0+ rd), + load_reg_from_mem(jh, traits::vl)); + } auto tmp297 = get_reg_Gp(cc, 64, false); mov(cc, tmp297, gen_ext(cc, 0, 64, false)); write_reg_to_mem(jh, tmp297, traits::vstart); @@ -87972,9 +87974,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_rv64i.cpp b/src/vm/asmjit/vm_rv64i.cpp index 523cb5e..9374dc8 100644 --- a/src/vm/asmjit/vm_rv64i.cpp +++ b/src/vm/asmjit/vm_rv64i.cpp @@ -3484,9 +3484,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/asmjit/vm_tgc5c.cpp b/src/vm/asmjit/vm_tgc5c.cpp index 0f0ff20..7ba7ec1 100644 --- a/src/vm/asmjit/vm_tgc5c.cpp +++ b/src/vm/asmjit/vm_tgc5c.cpp @@ -4723,9 +4723,8 @@ template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) { enum {TRAP_ID=1<<16}; code_word_t instr = 0; - phys_addr_t paddr(pc); auto *const data = (uint8_t *)&instr; - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read({address_type::LOGICAL, access_type::DEBUG_READ, arch::traits::IMEM, pc.val}, 4, data); if (res != iss::Ok) return ILLEGAL_FETCH; if (instr == 0x0000006f || (instr&0xffff)==0xa001) diff --git a/src/vm/interp/vm_rv32gc.cpp b/src/vm/interp/vm_rv32gc.cpp index 9e78a1f..5b405e8 100644 --- a/src/vm/interp/vm_rv32gc.cpp +++ b/src/vm/interp/vm_rv32gc.cpp @@ -359,7 +359,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -4876,6 +4876,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv32gcv.cpp b/src/vm/interp/vm_rv32gcv.cpp index 75c5358..c5e6994 100644 --- a/src/vm/interp/vm_rv32gcv.cpp +++ b/src/vm/interp/vm_rv32gcv.cpp @@ -1330,7 +1330,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -5942,7 +5942,9 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co else { uint16_t VLMAX = (uint16_t)(1 << ((uint16_t)(get_pow(traits::VLEN)) + (int16_t)(get_lmul_pow()) - (uint16_t)(get_sew_pow()))) & ~1; *vl = calculate_new_vl(uimm, VLMAX); - *(X+rd) = *vl; + if(rd != 0) { + *(X+rd) = *vl; + } *vstart = 0; } } @@ -29758,6 +29760,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv32i.cpp b/src/vm/interp/vm_rv32i.cpp index fe29de5..7447095 100644 --- a/src/vm/interp/vm_rv32i.cpp +++ b/src/vm/interp/vm_rv32i.cpp @@ -215,7 +215,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -1743,6 +1743,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv32imac.cpp b/src/vm/interp/vm_rv32imac.cpp index 49d201e..ca29721 100644 --- a/src/vm/interp/vm_rv32imac.cpp +++ b/src/vm/interp/vm_rv32imac.cpp @@ -264,7 +264,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -3145,6 +3145,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv64gc.cpp b/src/vm/interp/vm_rv64gc.cpp index 1619acb..ced250c 100644 --- a/src/vm/interp/vm_rv64gc.cpp +++ b/src/vm/interp/vm_rv64gc.cpp @@ -399,7 +399,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -6219,6 +6219,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv64gcv.cpp b/src/vm/interp/vm_rv64gcv.cpp index 7118e6f..efc747a 100644 --- a/src/vm/interp/vm_rv64gcv.cpp +++ b/src/vm/interp/vm_rv64gcv.cpp @@ -1370,7 +1370,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -7285,7 +7285,9 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co else { uint16_t VLMAX = (uint16_t)(1 << ((uint16_t)(get_pow(traits::VLEN)) + (int16_t)(get_lmul_pow()) - (uint16_t)(get_sew_pow()))) & ~1; *vl = calculate_new_vl(uimm, VLMAX); - *(X+rd) = *vl; + if(rd != 0) { + *(X+rd) = *vl; + } *vstart = 0; } } @@ -31101,6 +31103,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_rv64i.cpp b/src/vm/interp/vm_rv64i.cpp index 0e75e45..9ca2dc6 100644 --- a/src/vm/interp/vm_rv64i.cpp +++ b/src/vm/interp/vm_rv64i.cpp @@ -227,7 +227,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -2109,6 +2109,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/interp/vm_tgc5c.cpp b/src/vm/interp/vm_tgc5c.cpp index 779d616..5bc85f8 100644 --- a/src/vm/interp/vm_tgc5c.cpp +++ b/src/vm/interp/vm_tgc5c.cpp @@ -253,7 +253,7 @@ template class vm_impl : public iss::interp::vm_base { decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ - if (this->core.read(iss::address_type::PHYSICAL, pc.access, pc.space, pc.val, 4, data) != iss::Ok) + if (this->core.read({iss::address_type::LOGICAL, pc.access, arch::traits::IMEM, pc.val}, 4, data) != iss::Ok) return iss::Err; return iss::Ok; } @@ -2730,6 +2730,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co break; }// @suppress("No break at end of case") default: { + if(this->core.can_handle_unknown_instruction()) { + auto res = this->core.handle_unknown_instruction(pc.val, sizeof(instr), reinterpret_cast(&instr)); + if(std::get<0>(res)) { + *NEXT_PC = std::get<1>(res); + break; + } + } if(this->disass_enabled){ std::string mnemonic = "Illegal Instruction"; this->core.disass_output(pc.val, mnemonic); diff --git a/src/vm/vector_functions.h b/src/vm/vector_functions.h index de8c78f..83b1552 100644 --- a/src/vm/vector_functions.h +++ b/src/vm/vector_functions.h @@ -74,14 +74,14 @@ constexpr size_t map_index_size[9] = {std::numeric_limits::max(), inline bool softvec_read(void* core, uint64_t addr, uint64_t length, uint8_t* data) { // Read length bytes from addr into *data - iss::status status = static_cast(core)->read(iss::address_type::PHYSICAL, iss::access_type::READ, - 0 /*traits::MEM*/, addr, length, data); + iss::status status = static_cast(core)->read( + {iss::address_type::LOGICAL, iss::access_type::READ, 0 /*traits::MEM*/, addr}, length, data); return status == iss::Ok; } inline bool softvec_write(void* core, uint64_t addr, uint64_t length, uint8_t* data) { // Write length bytes from addr into *data - iss::status status = static_cast(core)->write(iss::address_type::PHYSICAL, iss::access_type::READ, - 0 /*traits::MEM*/, addr, length, data); + iss::status status = static_cast(core)->write( + {iss::address_type::LOGICAL, iss::access_type::WRITE, 0 /*traits::MEM*/, addr}, length, data); return status == iss::Ok; } template