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.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4d4b8c3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,181 @@ +name: CI + +on: + workflow_dispatch: + push: + paths: + - '**.hpp' + - '**.cpp' + - '**.h' + - '**.c' + - '**.S' + - '**CMakeLists.txt' + - '.github/workflows/**' + - 'conanfile.py' + pull_request: + paths: + - '**.hpp' + - '**.cpp' + - '**.h' + - '**.c' + - '**.S' + - '**CMakeLists.txt' + - '.github/workflows/**' + - 'conanfile.py' + +jobs: + cpp-compliance: + name: C++ Std Compliance (C++${{ matrix.cpp_std }}) + runs-on: ubuntu-24.04 + 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: Install dependencies + run: | + sudo apt-get install -y g++ python3-pip cmake llvm-19-dev + pip3 install conan + cmake --version + + - name: Configure + run: cmake --preset Release -B build -DCMAKE_CXX_STANDARD=${{ matrix.cpp_std }} -DWITH_LLVM=ON -DWITH_SYSTEM_LLVM=ON + + - name: Build + run: cmake --build build -j + + - name: Smoke test + run: ./build/riscv-sim -h + + # NOTE: .so filename is tied to VERSION in top-level CMakeLists.txt - update both together + - name: Upload binary + if: matrix.cpp_std == 20 + uses: actions/upload-artifact@v4 + with: + name: riscv-sim + path: | + build/riscv-sim + build/libdbt-rise-riscv.so.2.1.0 + + pmp-tests: + name: PMP Functional Tests + runs-on: ubuntu-24.04 + needs: cpp-compliance + steps: + - uses: actions/checkout@v4 + + - name: Install RISC-V toolchain + run: sudo apt-get install -y gcc-riscv64-unknown-elf + + - name: Download riscv-sim binary + uses: actions/download-artifact@v4 + with: + name: riscv-sim + + - name: Make binary executable + run: chmod +x riscv-sim + + - name: Build PMP CSR test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_csr_test \ + contrib/fw/pmp-csr-test/pmp_csr_test.S + + - name: rv64gc_m CSR test - interp (no PMP, expect exit 2) + run: | + LD_LIBRARY_PATH=. ./riscv-sim -f pmp_csr_test --isa rv64gc_m --backend interp || rc=$? + [ "${rc:-0}" -eq 2 ] + + - name: rv64gc_mp_64 CSR test - interp (with PMP) + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_csr_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP enforcement test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_enforce_test \ + contrib/fw/pmp-enforce-test/pmp_enforce_test.S + + - name: rv64gc_mp_64 enforcement test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_enforce_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP shift test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_shift_test \ + contrib/fw/pmp-shift-test/pmp_shift_test.S + + - name: rv64gc_mp_64 shift test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_shift_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP upper-cfg test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_upper_cfg_test \ + contrib/fw/pmp-upper-cfg-test/pmp_upper_cfg_test.S + + - name: rv64gc_mp_64 upper-cfg test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_upper_cfg_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP cfg2 test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_cfg2_test \ + contrib/fw/pmp-cfg2-test/pmp_cfg2_test.S + + - name: rv64gc_mp_64 cfg2 test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_cfg2_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP TOR test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_tor_test \ + contrib/fw/pmp-tor-test/pmp_tor_test.S + + - name: rv64gc_mp_64 TOR test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_tor_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP 64-entry pmpaddr test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_64entry_addr_test \ + contrib/fw/pmp-64entry-addr-test/pmp_64entry_addr_test.S + + - name: rv64gc_mp_64 64-entry pmpaddr test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_64entry_addr_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP 64-entry pmpcfg test firmware + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_64entry_cfg_test \ + contrib/fw/pmp-64entry-cfg-test/pmp_64entry_cfg_test.S + + - name: rv64gc_mp_64 64-entry pmpcfg test - interp + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_64entry_cfg_test --isa rv64gc_mp_64 --backend interp + + - name: Build PMP 8-entry guard test firmware (VP/S5 model) + run: | + riscv64-unknown-elf-gcc -nostdlib -march=rv64gc -mabi=lp64 \ + -Wl,-Ttext=0x10000,--no-dynamic-linker \ + -o pmp_8entry_guard_test \ + contrib/fw/pmp-8entry-guard-test/pmp_8entry_guard_test.S + + - name: rv64gc_mp_8 8-entry enforcement test - interp (VP/S5 model) + run: LD_LIBRARY_PATH=. ./riscv-sim -f pmp_8entry_guard_test --isa rv64gc_mp_8 --backend interp 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 08c10b2..7c76b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,31 +4,52 @@ 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) - +option(OPTIMIZE_FOR_NATIVE "Build with -march=native" OFF) +option(NO_GENERIC_CORES "Leave out the genric cores to improve build times" OFF) include(GNUInstallDirs) include(flink) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) +include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) +if(OPTIMIZE_FOR_NATIVE AND COMPILER_SUPPORTS_MARCH_NATIVE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") +endif() + +option(WITH_SYSTEM_LLVM "Use system-installed LLVM (llvm-dev from apt) instead of Conan-built" OFF) +set(LLVM_MAJOR_VERSION "19" CACHE STRING "System LLVM major version when WITH_SYSTEM_LLVM=ON") +if(WITH_SYSTEM_LLVM) + set(LLVM_DIR "/usr/lib/llvm-${LLVM_MAJOR_VERSION}/lib/cmake/llvm" CACHE PATH "" FORCE) + find_package(LLVM REQUIRED CONFIG BYPASS_PROVIDER) + message(STATUS "Found system LLVM ${LLVM_VERSION}") + if(NOT TARGET llvm-core::llvm-core) + add_library(llvm-core::llvm-core INTERFACE IMPORTED GLOBAL) + target_include_directories(llvm-core::llvm-core INTERFACE ${LLVM_INCLUDE_DIRS}) + target_compile_definitions(llvm-core::llvm-core INTERFACE ${LLVM_DEFINITIONS}) + target_link_libraries(llvm-core::llvm-core INTERFACE LLVM-${LLVM_VERSION_MAJOR}) + endif() + if(NOT WITH_LLVM) + set(WITH_LLVM ON CACHE BOOL "Build LLVM backend" FORCE) + endif() +endif() + include(FetchContent) if(NOT TARGET dbt-rise-core) FetchContent_Declare( dbt_rise_core_git GIT_REPOSITORY "https://github.com/Minres/DBT-RISE-Core.git" - #GIT_TAG "origin/develop" - GIT_TAG 0c7532f6 + GIT_TAG fa86b089 GIT_SHALLOW OFF UPDATE_DISCONNECTED NOT ${UPDATE_EXTERNAL_PROJECT} # When enabled, this option causes the update step to be skipped. ) FetchContent_GetProperties(dbt_rise_core_git) - if(NOT dbt_rise_core_git_POPULATED) - FetchContent_Populate(dbt_rise_core_git) - endif() - add_subdirectory(${dbt_rise_core_git_SOURCE_DIR} ${dbt_rise_core_git_BINARY_DIR}) + FetchContent_MakeAvailable(dbt_rise_core_git) endif() FetchContent_GetProperties(scc_git) list(APPEND CMAKE_MODULE_PATH ${scc_git_SOURCE_DIR}/cmake) @@ -48,63 +69,72 @@ endif() 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 - src/iss/arch/rv64i.cpp - src/iss/arch/rv64gc.cpp - src/iss/arch/rv64gcv.cpp src/iss/arch/tgc5c.cpp src/iss/mem/memory_if.cpp src/vm/interp/vm_tgc5c.cpp - src/vm/interp/vm_rv32i.cpp - src/vm/interp/vm_rv32imac.cpp - src/vm/interp/vm_rv32gc.cpp - src/vm/interp/vm_rv32gcv.cpp - src/vm/interp/vm_rv64i.cpp - src/vm/interp/vm_rv64gc.cpp - src/vm/interp/vm_rv64gcv.cpp src/iss/debugger/csr_names.cpp src/iss/semihosting/semihosting.cpp ) -if(TARGET yaml-cpp::yaml-cpp) +if(NOT NO_GENERIC_CORES) list(APPEND LIB_SOURCES - src/iss/plugin/cycle_estimate.cpp - src/iss/plugin/instruction_count.cpp + src/iss/arch/rv32i.cpp + src/iss/arch/rv32imac.cpp + src/iss/arch/rv32gc.cpp + src/iss/arch/rv32gcv.cpp + src/iss/arch/rv64i.cpp + src/iss/arch/rv64imac.cpp + src/iss/arch/rv64gc.cpp + src/iss/arch/rv64gcv.cpp + src/vm/interp/vm_rv32i.cpp + src/vm/interp/vm_rv32imac.cpp + src/vm/interp/vm_rv32gc.cpp + src/vm/interp/vm_rv32gcv.cpp + src/vm/interp/vm_rv64i.cpp + src/vm/interp/vm_rv64imac.cpp + src/vm/interp/vm_rv64gc.cpp + src/vm/interp/vm_rv64gc_mp.cpp + src/vm/interp/vm_rv64gcv.cpp ) endif() - -if(WITH_TCC) +if(TARGET yaml-cpp::yaml-cpp) list(APPEND LIB_SOURCES - src/vm/tcc/vm_tgc5c.cpp + src/iss/plugin/cycle_estimate.cpp + src/iss/plugin/instruction_count.cpp ) endif() if(WITH_LLVM) list(APPEND LIB_SOURCES src/vm/llvm/vm_tgc5c.cpp - src/vm/llvm/vm_rv32i.cpp - src/vm/llvm/vm_rv32imac.cpp - src/vm/llvm/vm_rv32gc.cpp - src/vm/llvm/vm_rv64i.cpp - src/vm/llvm/vm_rv64gc.cpp src/vm/llvm/fp_impl.cpp ) + if(NOT NO_GENERIC_CORES) + list(APPEND LIB_SOURCES + src/vm/llvm/vm_rv32i.cpp + src/vm/llvm/vm_rv32imac.cpp + src/vm/llvm/vm_rv32gc.cpp + src/vm/llvm/vm_rv64i.cpp + src/vm/llvm/vm_rv64gc.cpp + ) + endif() endif() if(WITH_ASMJIT) list(APPEND LIB_SOURCES src/vm/asmjit/vm_tgc5c.cpp - src/vm/asmjit/vm_rv32i.cpp - src/vm/asmjit/vm_rv32imac.cpp - src/vm/asmjit/vm_rv32gc.cpp - src/vm/asmjit/vm_rv32gcv.cpp - src/vm/asmjit/vm_rv64i.cpp - src/vm/asmjit/vm_rv64gc.cpp - src/vm/asmjit/vm_rv64gcv.cpp ) + if(NOT NO_GENERIC_CORES) + list(APPEND LIB_SOURCES + src/vm/asmjit/vm_rv32i.cpp + src/vm/asmjit/vm_rv32imac.cpp + src/vm/asmjit/vm_rv32gc.cpp + src/vm/asmjit/vm_rv32gcv.cpp + src/vm/asmjit/vm_rv64i.cpp + src/vm/asmjit/vm_rv64imac.cpp + src/vm/asmjit/vm_rv64gc.cpp + src/vm/asmjit/vm_rv64gcv.cpp + ) + endif() endif() if(IS_DIRECTORY "${PROJECT_SOURCE_DIR}/../dbt-rise-custom") @@ -120,18 +150,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 +164,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") @@ -184,7 +206,7 @@ install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package) INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers ) -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME} +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/iss COMPONENT ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory FILES_MATCHING # install only matched files PATTERN "*.h" # select header files @@ -238,11 +260,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,9 +276,10 @@ 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 sc_signals for interrupt delivery") + set(LIB_SOURCES src/sysc/core_complex.cpp - src/sysc/core_complex_mt.cpp src/sysc/register_cores.cpp src/sysc/register_rv32gcv.cpp src/sysc/register_rv64gcv.cpp @@ -271,20 +289,43 @@ 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 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 @@ -293,6 +334,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/README.md b/README.md index 0d6e7ef..7591d2f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![CI](https://github.com/Minres/DBT-RISE-RISCV/actions/workflows/ci.yml/badge.svg)](https://github.com/Minres/DBT-RISE-RISCV/actions/workflows/ci.yml) + # DBT-RISE-RISCV A instruction set simulator based on DBT-RISE implementing the RISC-V ISA. The project is hosted at https://github.com/Minres/DBT-RISE-RISCV . @@ -61,4 +63,4 @@ make -C build/Firmwares/hello-world/ ISA=imc BOARD=iss - JIT-backends for higher execution speeds - Built-in plugin support to inspect or manipulate architectural state before and after each instruction - Full GDB-server -- Easy integration into SystemC or similar (eg. Platform Architect) \ No newline at end of file +- Easy integration into SystemC or similar (eg. Platform Architect) diff --git a/conanfile.py b/conanfile.py index e87df7a..d6fd649 100644 --- a/conanfile.py +++ b/conanfile.py @@ -36,15 +36,14 @@ class Pkg(ConanFile): } def requirements(self): - self.requires("fmt/8.0.1") - self.requires("spdlog/1.9.2") + self.requires("fmt/12.1.0") + self.requires("spdlog/1.17.0") 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("elfio/3.12") + self.requires("lz4/1.10.0") + self.requires("yaml-cpp/0.9.0") + self.requires("jsoncpp/1.9.6") + 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/contrib/fw/pmp-64entry-addr-test/pmp_64entry_addr_test.S b/contrib/fw/pmp-64entry-addr-test/pmp_64entry_addr_test.S new file mode 100644 index 0000000..64fe595 --- /dev/null +++ b/contrib/fw/pmp-64entry-addr-test/pmp_64entry_addr_test.S @@ -0,0 +1,26 @@ +// Verify pmpaddr32 (CSR 0x3D0) is accessible - tests 64-entry pmpaddr support. +// Pass: readback matches written sentinel -> j . (exit 0) +// Fail: any trap (unregistered CSR) or readback mismatch -> semihosting SYS_EXIT (exit 2) + +.section .text +.globl _start +_start: + la t0, fail + csrw mtvec, t0 + + li t0, 0xDEAD + csrw 0x3D0, t0 // pmpaddr32 + csrr t1, 0x3D0 + bne t0, t1, fail + + j . // pass + +fail: + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . diff --git a/contrib/fw/pmp-64entry-cfg-test/pmp_64entry_cfg_test.S b/contrib/fw/pmp-64entry-cfg-test/pmp_64entry_cfg_test.S new file mode 100644 index 0000000..0336554 --- /dev/null +++ b/contrib/fw/pmp-64entry-cfg-test/pmp_64entry_cfg_test.S @@ -0,0 +1,34 @@ +// Verify pmpcfg4 (CSR 0x3A4, holds entries 32-39 on RV64) is accessible and persistent. +// Tests 64-entry pmpcfg registration. +// Pass: write 0x9F -> read back 0x9F -> write 0 -> read back 0 -> j . (exit 0) +// Fail: any trap or readback mismatch -> semihosting SYS_EXIT (exit 2) + +.section .text +.globl _start +_start: + la t0, fail + csrw mtvec, t0 + + // Write and verify a non-zero value + li t0, 0x9F + csrw 0x3A4, t0 // pmpcfg4 write + csrr t1, 0x3A4 // pmpcfg4 read + bne t0, t1, fail // must match + + // Clear and verify zero + li t0, 0 + csrw 0x3A4, t0 + csrr t1, 0x3A4 + bne t0, t1, fail + + j . // pass + +fail: + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . diff --git a/contrib/fw/pmp-8entry-guard-test/pmp_8entry_guard_test.S b/contrib/fw/pmp-8entry-guard-test/pmp_8entry_guard_test.S new file mode 100644 index 0000000..a739801 --- /dev/null +++ b/contrib/fw/pmp-8entry-guard-test/pmp_8entry_guard_test.S @@ -0,0 +1,50 @@ +// VP guard test: verify PMP enforcement works with only 8 entries (S5 hardware limit). +// Configures entry 0 to deny load from test_word; expects load-access fault. +// Also verifies pmpaddr8+ traps (outside the 8-entry window). +// +// Pass: phase2_trap fires (load denied) -> j . (exit 0) +// Fail: CSR trap, load succeeds, or unexpected behavior -> semihosting SYS_EXIT (exit 2) + +.macro semihosting_fail + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . +.endm + +.section .text +.globl _start +_start: + // phase1_trap: any CSR trap = PMP not available + la t0, phase1_trap + csrw mtvec, t0 + + // Configure entry 0: NA4, no R/W/X, locked + la t5, test_word + srli t1, t5, 2 + csrw pmpaddr0, t1 + + li t1, 0x90 // NA4(0x10) | L(0x80) + csrw pmpcfg0, t1 + + // phase2_trap: load fault = enforcement active = PASS + la t0, phase2_trap + csrw mtvec, t0 + + lw t1, 0(t5) // should fault: entry 0 denies read + + semihosting_fail // no fault -> FAIL + +phase1_trap: + semihosting_fail // CSR trap -> FAIL + +phase2_trap: + j . // load denied as expected -> PASS + + .align 2 +test_word: + .word 0xCAFECAFE diff --git a/contrib/fw/pmp-cfg2-test/pmp_cfg2_test.S b/contrib/fw/pmp-cfg2-test/pmp_cfg2_test.S new file mode 100644 index 0000000..7a125a0 --- /dev/null +++ b/contrib/fw/pmp-cfg2-test/pmp_cfg2_test.S @@ -0,0 +1,29 @@ +// Verify pmpcfg2 (entries 8-15) is accessible as a CSR on RV64. +// On RV64 valid pmpcfg CSRs are pmpcfg0 (entries 0-7) and pmpcfg2 (entries 8-15). +// +// Pass: pmpcfg2 readback == written value -> j . (exit 0) +// Fail: pmpcfg2 write traps OR readback wrong -> semihosting SYS_EXIT (exit 2) + +.section .text +.globl _start +_start: + la t0, fail + csrw mtvec, t0 + + // 0x18 per byte = NAPOT mode, no RWX, no lock; survives 0x9f byte mask + li t0, 0x1818181818181818 + csrw pmpcfg2, t0 + csrr t1, pmpcfg2 + bne t0, t1, fail + + j . // pass: ISS detects j . and exits 0 + +fail: + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . diff --git a/contrib/fw/pmp-csr-test/pmp_csr_test.S b/contrib/fw/pmp-csr-test/pmp_csr_test.S new file mode 100644 index 0000000..e363642 --- /dev/null +++ b/contrib/fw/pmp-csr-test/pmp_csr_test.S @@ -0,0 +1,32 @@ +// Verify pmpaddr0 is accessible as a CSR (no illegal-instruction trap on read/write). +// Pass: j . detected as JUMP_TO_SELF by ISS, exits 0. +// Fail: semihosting SYS_EXIT sequence, ISS exits non-zero. + +.section .text +.globl _start +_start: + // Install fail handler: any unexpected trap before the ecall path means the CSR + // is not available or behaves incorrectly + la t0, fail + csrw mtvec, t0 + + // Write a distinctive value to pmpaddr0 and verify the readback matches + li t0, 0xDEAD + csrw pmpaddr0, t0 + csrr t1, pmpaddr0 + bne t0, t1, fail + + j . // pass: ISS detects j . and exits 0 + +fail: + // Semihosting SYS_EXIT: the ISS checks for slli+ebreak+srai and intercepts + // before dispatching to mtvec. Must use 4-byte ebreak (not c.ebreak) so the + // check lands at the correct offsets (-4 and +4 from the ebreak address). + li a0, 0x18 // SYS_EXIT + .option push + .option norvc // force 4-byte ebreak (0x00100073), not 2-byte c.ebreak + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . // fallback if semihosting is not configured diff --git a/contrib/fw/pmp-enforce-test/pmp_enforce_test.S b/contrib/fw/pmp-enforce-test/pmp_enforce_test.S new file mode 100644 index 0000000..549f133 --- /dev/null +++ b/contrib/fw/pmp-enforce-test/pmp_enforce_test.S @@ -0,0 +1,52 @@ +// PMP enforcement test - entry 0 (pmpaddr0 + pmpcfg0 byte 0). +// Tests that pmpcfg naming bugs 1+2 in pmp.h are fixed: +// Bug 1: read_pmpcfg reads pmpaddr[] instead of pmpcfg[] +// Bug 2: write_pmpcfg writes pmpaddr[] instead of pmpcfg[] +// +// Pass: PMP denies load -> load fault fires -> j . (exit 0) +// Fail: any CSR trap, OR load succeeds without fault -> semihosting SYS_EXIT (exit 2) + +.macro semihosting_fail + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . +.endm + +.section .text +.globl _start +_start: + // phase1_trap: CSR write trapped - PMP not available + la t0, phase1_trap + csrw mtvec, t0 + + // Configure pmpaddr0 = test_word >> 2 (NA4: covers exactly 4 bytes at test_word) + la t5, test_word + srli t1, t5, 2 + csrw pmpaddr0, t1 + + // pmpcfg0 byte 0 = 0x90 = NA4 (0x10) | L (0x80), no R/W/X permissions + li t1, 0x90 + csrw pmpcfg0, t1 + + // phase2_trap: load fault fired - PMP enforcement active = PASS + la t0, phase2_trap + csrw mtvec, t0 + + lw t1, 0(t5) // should fault: PMP denies read + + semihosting_fail // no fault: enforcement did not fire -> FAIL + +phase1_trap: + semihosting_fail // CSR trapped: PMP unavailable -> FAIL + +phase2_trap: + j . // load denied as expected -> PASS + + .align 2 +test_word: + .word 0xCAFECAFE diff --git a/contrib/fw/pmp-shift-test/pmp_shift_test.S b/contrib/fw/pmp-shift-test/pmp_shift_test.S new file mode 100644 index 0000000..bbb15bb --- /dev/null +++ b/contrib/fw/pmp-shift-test/pmp_shift_test.S @@ -0,0 +1,54 @@ +// PMP shift test - entry 1 (pmpaddr1 + pmpcfg0 byte 1). +// Verifies that pmpcfg byte extraction uses the correct shift: (i % cfg_reg_size) * 8. +// +// For entry 1, byte 1 of pmpcfg0 = 0x90 (NA4|L), written as 0x9000 to pmpcfg0. +// A wrong shift of 1 bit instead of 8 bits reads 0x4800, which has no PMP_A bits +// set, so any_active stays false and enforcement is skipped. +// +// Pass: PMP denies load -> load fault fires -> j . (exit 0) +// Fail: any CSR trap, OR load succeeds without fault -> semihosting SYS_EXIT (exit 2) + +.macro semihosting_fail + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . +.endm + +.section .text +.globl _start +_start: + // phase1_trap: CSR write trapped - PMP not available + la t0, phase1_trap + csrw mtvec, t0 + + // Configure pmpaddr1 = test_word2 >> 2 (NA4) + la t5, test_word2 + srli t1, t5, 2 + csrw pmpaddr1, t1 + + // pmpcfg0 byte 1 = 0x90 -> write 0x9000 to pmpcfg0 + li t1, 0x9000 + csrw pmpcfg0, t1 + + // phase2_trap: load fault fired - PMP enforcement active = PASS + la t0, phase2_trap + csrw mtvec, t0 + + lw t1, 0(t5) // should fault: PMP denies read + + semihosting_fail // no fault: enforcement did not fire -> FAIL + +phase1_trap: + semihosting_fail // CSR trapped: PMP unavailable -> FAIL + +phase2_trap: + j . // load denied as expected -> PASS + + .align 2 +test_word2: + .word 0xCAFECAFE diff --git a/contrib/fw/pmp-tor-test/pmp_tor_test.S b/contrib/fw/pmp-tor-test/pmp_tor_test.S new file mode 100644 index 0000000..b9001a9 --- /dev/null +++ b/contrib/fw/pmp-tor-test/pmp_tor_test.S @@ -0,0 +1,56 @@ +// Verify that a partial-overlap load (sectors spanning a TOR region boundary) is denied. +// pmpaddr0 sets the TOR base; pmpaddr1/pmpcfg0[1] set a locked read-only TOR region. +// An 8-byte load at test_region covers two 4-byte sectors: +// sector 0: test_region+0 (below TOR base -> outside range) +// sector 1: test_region+4 (inside TOR range) +// Correct behaviour: partial overlap -> PMP denies -> load fault fires. +// +// Pass: load fault fires -> j . (exit 0) +// Fail: load succeeds without fault -> semihosting SYS_EXIT (exit 2) + +.section .text +.globl _start +_start: + la t0, fail + csrw mtvec, t0 + + // pmpaddr0 = (test_region+4) >> 2 (TOR base for entry 1) + la t5, test_region + addi t1, t5, 4 + srli t1, t1, 2 + csrw pmpaddr0, t1 + + // pmpaddr1 = (test_region+12) >> 2 (TOR top for entry 1) + addi t1, t5, 12 + srli t1, t1, 2 + csrw pmpaddr1, t1 + + // pmpcfg0: byte 1 = 0x89 (TOR|L|R) -> locked read-only TOR [test_region+4, test_region+12) + li t1, 0x8900 + csrw pmpcfg0, t1 + + la t0, pmp_fault + csrw mtvec, t0 + + // 8-byte load at test_region: sector 0 is outside range, sector 1 is inside. + // PMP must deny (partial overlap). + ld t2, 0(t5) + + // No fault fired -> bug present +fail: + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . + +pmp_fault: + j . // load denied as expected -> PASS + + .align 3 // 8-byte align for ld +test_region: + .quad 0x1234567890ABCDEF + .quad 0xC001CAFEDEADBEEF diff --git a/contrib/fw/pmp-upper-cfg-test/pmp_upper_cfg_test.S b/contrib/fw/pmp-upper-cfg-test/pmp_upper_cfg_test.S new file mode 100644 index 0000000..7c7e524 --- /dev/null +++ b/contrib/fw/pmp-upper-cfg-test/pmp_upper_cfg_test.S @@ -0,0 +1,27 @@ +// Verify that RV64 pmpcfg0 upper 32 bits (cfg bytes 4-7) are preserved on write. +// On RV64 a pmpcfg register is 64 bits and holds 8 config bytes (entries 0-7). +// A write mask narrower than reg_t silently zeroes bytes 4-7. +// +// Pass: readback == written value -> j . (exit 0) +// Fail: readback != written value -> semihosting SYS_EXIT (exit 2) + +.section .text +.globl _start +_start: + // 0x18 per byte = NAPOT mode, no RWX, no lock; survives 0x9f byte mask + li t0, 0x1818181818181818 + csrw pmpcfg0, t0 + csrr t1, pmpcfg0 + bne t0, t1, fail + + j . // pass: ISS detects j . and exits 0 + +fail: + li a0, 0x18 + .option push + .option norvc + slli zero, zero, 0x1f + ebreak + srai zero, zero, 7 + .option pop + j . diff --git a/contrib/instr/RV64IMAC_instr.yaml b/contrib/instr/RV64IMAC_instr.yaml new file mode 100644 index 0000000..f801c62 --- /dev/null +++ b/contrib/instr/RV64IMAC_instr.yaml @@ -0,0 +1,977 @@ + +RVI: + LUI: + index: 0 + encoding: 0b00000000000000000000000000110111 + mask: 0b00000000000000000000000001111111 + size: 32 + branch: false + delay: 1 + AUIPC: + index: 1 + encoding: 0b00000000000000000000000000010111 + mask: 0b00000000000000000000000001111111 + size: 32 + branch: false + delay: 1 + JAL: + index: 2 + encoding: 0b00000000000000000000000001101111 + mask: 0b00000000000000000000000001111111 + size: 32 + branch: true + delay: 1 + JALR: + index: 3 + encoding: 0b00000000000000000000000001100111 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BEQ: + index: 4 + encoding: 0b00000000000000000000000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BNE: + index: 5 + encoding: 0b00000000000000000001000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BLT: + index: 6 + encoding: 0b00000000000000000100000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BGE: + index: 7 + encoding: 0b00000000000000000101000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BLTU: + index: 8 + encoding: 0b00000000000000000110000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + BGEU: + index: 9 + encoding: 0b00000000000000000111000001100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: true + delay: [1,1] + LB: + index: 10 + encoding: 0b00000000000000000000000000000011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + LH: + index: 11 + encoding: 0b00000000000000000001000000000011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + LW: + index: 12 + encoding: 0b00000000000000000010000000000011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + LBU: + index: 13 + encoding: 0b00000000000000000100000000000011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + LHU: + index: 14 + encoding: 0b00000000000000000101000000000011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SB: + index: 15 + encoding: 0b00000000000000000000000000100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SH: + index: 16 + encoding: 0b00000000000000000001000000100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SW: + index: 17 + encoding: 0b00000000000000000010000000100011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + ADDI: + index: 18 + encoding: 0b00000000000000000000000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLTI: + index: 19 + encoding: 0b00000000000000000010000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLTIU: + index: 20 + encoding: 0b00000000000000000011000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + XORI: + index: 21 + encoding: 0b00000000000000000100000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + ORI: + index: 22 + encoding: 0b00000000000000000110000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + ANDI: + index: 23 + encoding: 0b00000000000000000111000000010011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLLI: + index: 24 + encoding: 0b00000000000000000001000000010011 + mask: 0b11111100000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRLI: + index: 25 + encoding: 0b00000000000000000101000000010011 + mask: 0b11111100000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRAI: + index: 26 + encoding: 0b01000000000000000101000000010011 + mask: 0b11111100000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + ADD: + index: 27 + encoding: 0b00000000000000000000000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SUB: + index: 28 + encoding: 0b01000000000000000000000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLL: + index: 29 + encoding: 0b00000000000000000001000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLT: + index: 30 + encoding: 0b00000000000000000010000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SLTU: + index: 31 + encoding: 0b00000000000000000011000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + XOR: + index: 32 + encoding: 0b00000000000000000100000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SRL: + index: 33 + encoding: 0b00000000000000000101000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + SRA: + index: 34 + encoding: 0b01000000000000000101000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + OR: + index: 35 + encoding: 0b00000000000000000110000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + AND: + index: 36 + encoding: 0b00000000000000000111000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + FENCE: + index: 37 + encoding: 0b00000000000000000000000000001111 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + ECALL: + index: 38 + encoding: 0b00000000000000000000000001110011 + mask: 0b11111111111111111111111111111111 + attributes: [[name:no_cont]] + size: 32 + branch: false + delay: 1 + EBREAK: + index: 39 + encoding: 0b00000000000100000000000001110011 + mask: 0b11111111111111111111111111111111 + attributes: [[name:no_cont]] + size: 32 + branch: false + delay: 1 + MRET: + index: 40 + encoding: 0b00110000001000000000000001110011 + mask: 0b11111111111111111111111111111111 + attributes: [[name:no_cont]] + size: 32 + branch: false + delay: 1 + WFI: + index: 41 + encoding: 0b00010000010100000000000001110011 + mask: 0b11111111111111111111111111111111 + size: 32 + branch: false + delay: 1 + LWU: + index: 42 + encoding: 0b00000000000000000110000000000011 + mask: 0b00000000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + LD: + index: 43 + encoding: 0b00000000000000000011000000000011 + mask: 0b00000000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SD: + index: 44 + encoding: 0b00000000000000000011000000100011 + mask: 0b00000000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + ADDIW: + index: 45 + encoding: 0b00000000000000000000000000011011 + mask: 0b00000000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SLLIW: + index: 46 + encoding: 0b00000000000000000001000000011011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRLIW: + index: 47 + encoding: 0b00000000000000000101000000011011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRAIW: + index: 48 + encoding: 0b01000000000000000101000000011011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + ADDW: + index: 49 + encoding: 0b00000000000000000000000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SUBW: + index: 50 + encoding: 0b01000000000000000000000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SLLW: + index: 51 + encoding: 0b00000000000000000001000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRLW: + index: 52 + encoding: 0b00000000000000000101000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SRAW: + index: 53 + encoding: 0b01000000000000000101000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 +Zicsr: + CSRRW: + index: 54 + encoding: 0b00000000000000000001000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + CSRRS: + index: 55 + encoding: 0b00000000000000000010000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + CSRRC: + index: 56 + encoding: 0b00000000000000000011000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + CSRRWI: + index: 57 + encoding: 0b00000000000000000101000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + CSRRSI: + index: 58 + encoding: 0b00000000000000000110000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 + CSRRCI: + index: 59 + encoding: 0b00000000000000000111000001110011 + mask: 0b00000000000000000111000001111111 + size: 32 + branch: false + delay: 1 +Zifencei: + FENCE_I: + index: 60 + encoding: 0b00000000000000000001000000001111 + mask: 0b00000000000000000111000001111111 + attributes: [[name:flush]] + size: 32 + branch: false + delay: 1 +RVM: + MUL: + index: 61 + encoding: 0b00000010000000000000000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + MULH: + index: 62 + encoding: 0b00000010000000000001000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + MULHSU: + index: 63 + encoding: 0b00000010000000000010000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + MULHU: + index: 64 + encoding: 0b00000010000000000011000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + DIV: + index: 65 + encoding: 0b00000010000000000100000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + DIVU: + index: 66 + encoding: 0b00000010000000000101000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + REM: + index: 67 + encoding: 0b00000010000000000110000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + REMU: + index: 68 + encoding: 0b00000010000000000111000000110011 + mask: 0b11111110000000000111000001111111 + size: 32 + branch: false + delay: 1 + MULW: + index: 69 + encoding: 0b00000010000000000000000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + DIVW: + index: 70 + encoding: 0b00000010000000000100000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + DIVUW: + index: 71 + encoding: 0b00000010000000000101000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + REMW: + index: 72 + encoding: 0b00000010000000000110000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + REMUW: + index: 73 + encoding: 0b00000010000000000111000000111011 + mask: 0b11111110000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 +RVA: + LRW: + index: 74 + encoding: 0b00010000000000000010000000101111 + mask: 0b11111001111100000111000001111111 + size: 32 + branch: false + delay: 1 + SCW: + index: 75 + encoding: 0b00011000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOSWAPW: + index: 76 + encoding: 0b00001000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOADDW: + index: 77 + encoding: 0b00000000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOXORW: + index: 78 + encoding: 0b00100000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOANDW: + index: 79 + encoding: 0b01100000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOORW: + index: 80 + encoding: 0b01000000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOMINW: + index: 81 + encoding: 0b10000000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOMAXW: + index: 82 + encoding: 0b10100000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOMINUW: + index: 83 + encoding: 0b11000000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + AMOMAXUW: + index: 84 + encoding: 0b11100000000000000010000000101111 + mask: 0b11111000000000000111000001111111 + size: 32 + branch: false + delay: 1 + LRD: + index: 85 + encoding: 0b00010000000000000011000000101111 + mask: 0b11111001111100000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + SCD: + index: 86 + encoding: 0b00011000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOSWAPD: + index: 87 + encoding: 0b00001000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOADDD: + index: 88 + encoding: 0b00000000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOXORD: + index: 89 + encoding: 0b00100000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOANDD: + index: 90 + encoding: 0b01100000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOORD: + index: 91 + encoding: 0b01000000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOMIND: + index: 92 + encoding: 0b10000000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOMAXD: + index: 93 + encoding: 0b10100000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOMINUD: + index: 94 + encoding: 0b11000000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 + AMOMAXUD: + index: 95 + encoding: 0b11100000000000000011000000101111 + mask: 0b11111000000000000111000001111111 + attributes: [[name:enable, value:1]] + size: 32 + branch: false + delay: 1 +Zca: + C__ADDI4SPN: + index: 96 + encoding: 0b0000000000000000 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__LW: + index: 97 + encoding: 0b0100000000000000 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__LD: + index: 98 + encoding: 0b0110000000000000 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__SW: + index: 99 + encoding: 0b1100000000000000 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__SD: + index: 100 + encoding: 0b1110000000000000 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__ADDI: + index: 101 + encoding: 0b0000000000000001 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__NOP: + index: 102 + encoding: 0b0000000000000001 + mask: 0b1110111110000011 + size: 16 + branch: false + delay: 1 + C__ADDIW: + index: 103 + encoding: 0b0010000000000001 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__LI: + index: 104 + encoding: 0b0100000000000001 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__LUI: + index: 105 + encoding: 0b0110000000000001 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__ADDI16SP: + index: 106 + encoding: 0b0110000100000001 + mask: 0b1110111110000011 + size: 16 + branch: false + delay: 1 + __reserved_clui: + index: 107 + encoding: 0b0110000000000001 + mask: 0b1111000001111111 + size: 16 + branch: false + delay: 1 + C__SRLI: + index: 108 + encoding: 0b1000000000000001 + mask: 0b1110110000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__SRAI: + index: 109 + encoding: 0b1000010000000001 + mask: 0b1110110000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__ANDI: + index: 110 + encoding: 0b1000100000000001 + mask: 0b1110110000000011 + size: 16 + branch: false + delay: 1 + C__SUB: + index: 111 + encoding: 0b1000110000000001 + mask: 0b1111110001100011 + size: 16 + branch: false + delay: 1 + C__XOR: + index: 112 + encoding: 0b1000110000100001 + mask: 0b1111110001100011 + size: 16 + branch: false + delay: 1 + C__OR: + index: 113 + encoding: 0b1000110001000001 + mask: 0b1111110001100011 + size: 16 + branch: false + delay: 1 + C__AND: + index: 114 + encoding: 0b1000110001100001 + mask: 0b1111110001100011 + size: 16 + branch: false + delay: 1 + C__SUBW: + index: 115 + encoding: 0b1001110000000001 + mask: 0b1111110001100011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__ADDW: + index: 116 + encoding: 0b1001110000100001 + mask: 0b1111110001100011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__J: + index: 117 + encoding: 0b1010000000000001 + mask: 0b1110000000000011 + size: 16 + branch: true + delay: 1 + C__BEQZ: + index: 118 + encoding: 0b1100000000000001 + mask: 0b1110000000000011 + size: 16 + branch: true + delay: [1,1] + C__BNEZ: + index: 119 + encoding: 0b1110000000000001 + mask: 0b1110000000000011 + size: 16 + branch: true + delay: [1,1] + C__SLLI: + index: 120 + encoding: 0b0000000000000010 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__LWSP: + index: 121 + encoding: 0b0100000000000010 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__LDSP: + index: 122 + encoding: 0b0110000000000010 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + C__MV: + index: 123 + encoding: 0b1000000000000010 + mask: 0b1111000000000011 + size: 16 + branch: false + delay: 1 + C__JR: + index: 124 + encoding: 0b1000000000000010 + mask: 0b1111000001111111 + size: 16 + branch: true + delay: 1 + __reserved_cmv: + index: 125 + encoding: 0b1000000000000010 + mask: 0b1111111111111111 + size: 16 + branch: false + delay: 1 + C__ADD: + index: 126 + encoding: 0b1001000000000010 + mask: 0b1111000000000011 + size: 16 + branch: false + delay: 1 + C__JALR: + index: 127 + encoding: 0b1001000000000010 + mask: 0b1111000001111111 + size: 16 + branch: true + delay: 1 + C__EBREAK: + index: 128 + encoding: 0b1001000000000010 + mask: 0b1111111111111111 + size: 16 + branch: false + delay: 1 + C__SWSP: + index: 129 + encoding: 0b1100000000000010 + mask: 0b1110000000000011 + size: 16 + branch: false + delay: 1 + C__SDSP: + index: 130 + encoding: 0b1110000000000010 + mask: 0b1110000000000011 + attributes: [[name:enable, value:1]] + size: 16 + branch: false + delay: 1 + DII: + index: 131 + encoding: 0b0000000000000000 + mask: 0b1111111111111111 + size: 16 + branch: false + delay: 1 + diff --git a/gen_input/ISA b/gen_input/ISA index c0d5707..4cb1545 160000 --- a/gen_input/ISA +++ b/gen_input/ISA @@ -1 +1 @@ -Subproject commit c0d570783c2c36080195496e6bcf5c64e9960601 +Subproject commit 4cb1545f57007dca155f3453ff9961325aac7246 diff --git a/gen_input/cores.core_desc b/gen_input/cores.core_desc index d59e0cc..21b25cd 100644 --- a/gen_input/cores.core_desc +++ b/gen_input/cores.core_desc @@ -10,9 +10,7 @@ import "ISA/RVV/RVV.core_desc" Core RV32I provides RVI, Zicsr, Zifencei { architectural_state { XLEN=32; - // definitions for the architecture wrapper - // XL ZYXWVUTSRQPONMLKJIHGFEDCBA - unsigned MISA_VAL = 0b01000000000000000000000100000000; + unsigned MISA_VAL = 0x40000100; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } @@ -21,9 +19,7 @@ Core RV32I provides RVI, Zicsr, Zifencei { Core RV32IMAC provides RVI, Zicsr, Zifencei, RVM, RVA, Zca { architectural_state { XLEN=32; - // definitions for the architecture wrapper - // XL ZYXWVUTSRQPONMLKJIHGFEDCBA - unsigned MISA_VAL = 0b01000000000000000001000100000101; + unsigned MISA_VAL = 0x40001105; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } @@ -33,9 +29,7 @@ Core RV32GC provides RVI, Zicsr, Zifencei, RVM, RVA, Zca, Zcf, Zcd, RVSMode { architectural_state { XLEN=32; FLEN=64; - // definitions for the architecture wrapper - // XL ZYXWVUTSRQPONMLKJIHGFEDCBA - unsigned MISA_VAL = 0b01000000000000000001000100101101; + unsigned MISA_VAL = 0x4000112d; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } @@ -47,9 +41,7 @@ Core RV32GCV provides RVI, Zicsr, Zifencei, RVM, RVA, Zca, Zcf, Zcd, RVSMode, RV FLEN=64; VLEN=256; ELEN=32; - // definitions for the architecture wrapper - // XL ZYXWVUTSRQPONMLKJIHGFEDCBA - unsigned MISA_VAL = 0b01000000000000000001000100101101; + unsigned MISA_VAL = 0x4020112d; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } @@ -58,8 +50,16 @@ Core RV32GCV provides RVI, Zicsr, Zifencei, RVM, RVA, Zca, Zcf, Zcd, RVSMode, RV Core RV64I provides RVI, Zicsr, Zifencei { architectural_state { XLEN=64; - // definitions for the architecture wrapper - unsigned MISA_VAL = 0x80000100; + unsigned MISA_VAL = 0x8000000000000100; + unsigned int MARCHID_VAL = 0x00000000; + unsigned int CLIC_NUM_IRQ = 0; + } +} + +Core RV64IMAC provides RVI, Zicsr, Zifencei, RVM, RVA, Zca { + architectural_state { + XLEN=64; + unsigned MISA_VAL = 0x8000000000001105; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } @@ -69,7 +69,6 @@ Core RV64GC provides RVI, Zicsr, Zifencei, RVM, RVA, Zca, Zcd, RVSMode { architectural_state { XLEN=64; FLEN=64; - // definitions for the architecture wrapper unsigned MISA_VAL = 0x800000000000112d; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; @@ -82,13 +81,12 @@ Core RV64GCV provides RVI, Zicsr, Zifencei, RVM, RVA, Zca, Zcd, RVSMode, RVVBase FLEN=64; VLEN=512; ELEN=64; - // definitions for the architecture wrapper - unsigned MISA_VAL = 0x800000000000112d; + unsigned MISA_VAL = 0x800000000020112d; unsigned int MARCHID_VAL = 0x00000000; unsigned int CLIC_NUM_IRQ = 0; } } /* -for b in interp asmjit; do for i in RV32I RV32IMAC RV32IMACF RV32GC RV64I RV64GC; do ./build/TGC-GEN/scripts/generate_iss.sh -b $b -o . -m src -r gen_input -t gen_input/templates -c $i gen_input/cores.core_desc; done ; done +for b in interp asmjit; do for i in RV32I RV32IMAC RV32GC RV32GCV RV64I RV64IMAC RV64GC RV64GCV; do ./build/TGC-GEN/scripts/generate_iss.sh -b $b -o . -m src -r gen_input -t gen_input/templates -c $i gen_input/cores.core_desc; done ; done */ diff --git a/gen_input/templates/CORENAME.h.gtl b/gen_input/templates/CORENAME.h.gtl index f9e729f..ffc395d 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_ @@ -81,6 +90,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct ${coreDef.name}_regs {<% registers.each { reg -> if(reg.size>64) {%> <% if(reg.size>128) {%>alignas(16) <%}%>uint8_t ${reg.name}[${reg.size/8}] = {0};<% @@ -134,8 +145,6 @@ if(vtype != null) {%> <%}%> }; -struct ${coreDef.name.toLowerCase()}; - template <> struct traits<${coreDef.name.toLowerCase()}> { constexpr static char const* const core_type = "${coreDef.name}"; @@ -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/CORENAME_instr.yaml.gtl b/gen_input/templates/CORENAME_instr.yaml.gtl index d9fdcbf..3902446 100644 --- a/gen_input/templates/CORENAME_instr.yaml.gtl +++ b/gen_input/templates/CORENAME_instr.yaml.gtl @@ -13,7 +13,11 @@ ${name}: <% instrList.each { %> ${it.instruction.name}: index: ${index++} encoding: ${it.encoding} - mask: ${it.mask}<%if(it.attributes.size) {%> + mask: ${it.mask} + bitfields:<% it.instruction.encoding.fields.each { if(it instanceof com.minres.coredsl.coreDsl.BitValue) { %> + - ${it.value.size}'b${it.value.toString(2).replace(' ', '0')} <% } else { %> + - ${it.name}[${it.startIndex.value}:${it.endIndex.value}]<% } } + if(it.attributes.size) {%> attributes: ${it.attributes}<%}%> size: ${it.length} branch: ${it.modifiesPC} diff --git a/gen_input/templates/CORENAME_sysc.cpp.gtl b/gen_input/templates/CORENAME_sysc.cpp.gtl index 5882e57..9e99eec 100644 --- a/gen_input/templates/CORENAME_sysc.cpp.gtl +++ b/gen_input/templates/CORENAME_sysc.cpp.gtl @@ -38,6 +38,10 @@ #include #include #include +<% if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") { %> +#include +#include +<%}%> <% def array_count = coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e"? 3 : 2; %> @@ -59,8 +63,11 @@ volatile std::array ${coreDef.name.toLowerCase()}_init = { auto* cpu = new core2sc_adapter>(cc); return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; })<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>, - iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}_mu_p_clic_pmp:interp", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}_clic_pmp:interp", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { auto* cpu = new core2sc_adapter>(cc); + cpu->memories.insert_before_last(std::make_unique>(cpu->get_priv_if())); + iss::mem::clic_config ccfg{.clic_base=0xc0000000, .clic_int_ctl_bits=4, .clic_num_irq=16, .clic_num_trigger=0, .nmode=true}; + cpu->memories.insert_before_last(std::make_unique::reg_t>>(cpu->get_priv_if(), ccfg)); return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; })<%}%> }; @@ -77,8 +84,11 @@ volatile std::array ${coreDef.name.toLowerCase()}_init = { auto* cpu = new core2sc_adapter>(cc); return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; })<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>, - iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}_mu_p_clic_pmp:llvm", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { + iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}_clic_pmp:llvm", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { auto* cpu = new core2sc_adapter>(cc); + cpu->memories.insert_before_last(std::make_unique>(cpu->get_priv_if())); + iss::mem::clic_config ccfg{.clic_base=0xc0000000, .clic_int_ctl_bits=4, .clic_num_irq=16, .clic_num_trigger=0, .nmode=true}; + cpu->memories.insert_before_last(std::make_unique::reg_t>>(cpu->get_priv_if(), ccfg)); return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; })<%}%> }; @@ -104,6 +114,9 @@ volatile std::array ${coreDef.name.toLowerCase()}_init = { })<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>, iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}_mu_p_clic_pmp:asmjit", [](unsigned gdb_port, sysc::riscv::core_complex_if* cc) -> iss_factory::base_t { auto* cpu = new core2sc_adapter>(cc); + cpu->memories.insert_before_last(std::make_unique>(cpu->get_priv_if())); + iss::mem::clic_config ccfg{.clic_base=0xc0000000, .clic_int_ctl_bits=4, .clic_num_irq=16, .clic_num_trigger=0, .nmode=true}; + cpu->memories.insert_before_last(std::make_unique::reg_t>>(cpu->get_priv_if(), ccfg)); return {sysc::core_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; })<%}%> }; diff --git a/gen_input/templates/asmjit/CORENAME.cpp.gtl b/gen_input/templates/asmjit/CORENAME.cpp.gtl index 25af08d..4d1c614 100644 --- a/gen_input/templates/asmjit/CORENAME.cpp.gtl +++ b/gen_input/templates/asmjit/CORENAME.cpp.gtl @@ -346,7 +346,8 @@ private: } }; -template vm_impl::vm_impl() { this(new ARCH()); } +template vm_impl::vm_impl() +: vm_base(std::make_unique()) {} template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) @@ -365,9 +366,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..c994927 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -56,7 +56,6 @@ if(vector) {%> #include #include #include -#include #include @@ -295,7 +294,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; } @@ -356,12 +355,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co auto& instr = this->core.reg.instruction; // we fetch at max 4 byte, alignment is 2 auto *const data = reinterpret_cast(&instr); + this->core.enable_disass(this->disass_enabled); while(!this->core.should_stop() && !(is_icount_limit_enabled(cond) && icount >= count_limit) && !(is_fcount_limit_enabled(cond) && fetch_count >= count_limit)){ if(this->debugging_enabled()) - this->tgt_adapter->check_continue(*PC); + this->tgt_adapter->check_break_on_pc(*PC); pc.val=*PC; if(fetch_ins(pc, data)!=iss::Ok){ if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits::max()); @@ -377,7 +377,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co inst_id = instr_descr[inst_index].op; // pre execution stuff - this->core.reg.last_branch = 0; + this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); try{ switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %> @@ -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); @@ -442,10 +449,17 @@ std::unique_ptr create(arch::${coreD } // namespace interp } // namespace iss -#include +#include <% if(instructions.find{it.instruction.name.toLowerCase() == "sret"}) {%> +#include <%}%> #include -#include #include +<% if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") { %> +#include +#include +<%}%> +<% +def array_count = coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e"? 3 : 2; +%> namespace iss { namespace { <% if(instructions.find{it.instruction.name.toLowerCase() == "sret"}) {%> @@ -459,8 +473,8 @@ volatile std::array dummy = { cpu->set_semihosting_callback(*cb); } return {cpu_ptr{cpu}, vm_ptr{vm}}; - }),<% } else { %> -volatile std::array dummy = {<%}%> + }),<%} else {%> +volatile std::array dummy = {<%}%> core_factory::instance().register_creator("${coreDef.name.toLowerCase()}_m:interp", [](unsigned port, void* init_data) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); @@ -480,7 +494,20 @@ volatile std::array dummy = {<%}%> cpu->set_semihosting_callback(*cb); } return {cpu_ptr{cpu}, vm_ptr{vm}}; - }) + })<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>, + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}_clic_pmp:interp", [](unsigned port, void* init_data) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_mu_p(); + cpu->memories.insert_before_last(std::make_unique>(cpu->get_priv_if())); + iss::mem::clic_config ccfg{.clic_base=0xc0000000, .clic_int_ctl_bits=4, .clic_num_irq=16, .clic_num_trigger=0, .nmode=true}; + cpu->memories.insert_before_last(std::make_unique::reg_t>>(cpu->get_priv_if(), ccfg)); + auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + if(init_data){ + auto* cb = reinterpret_cast::reg_t>*>(init_data); + cpu->set_semihosting_callback(*cb); + } + return {cpu_ptr{cpu}, vm_ptr{vm}}; + })<%}%> }; } } diff --git a/gen_input/templates/llvm/CORENAME.cpp.gtl b/gen_input/templates/llvm/CORENAME.cpp.gtl index 3b63455..6f4e8ce 100644 --- a/gen_input/templates/llvm/CORENAME.cpp.gtl +++ b/gen_input/templates/llvm/CORENAME.cpp.gtl @@ -250,7 +250,8 @@ template void debug_fn(CODE_WORD instr) { instr = 2 * x; } -template vm_impl::vm_impl() { this(new ARCH()); } +template vm_impl::vm_impl() +: vm_base(std::make_unique()) {} template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) @@ -271,11 +272,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/softvector b/softvector index eee635c..2278733 160000 --- a/softvector +++ b/softvector @@ -1 +1 @@ -Subproject commit eee635c183d73d78450e4b996b49ce22b7629c49 +Subproject commit 22787332251bf0688c732b0ffd43817ed6a04c0b diff --git a/src/iss/arch/hwl.h b/src/iss/arch/hwl.h index 6694a40..7bacb38 100644 --- a/src/iss/arch/hwl.h +++ b/src/iss/arch/hwl.h @@ -47,28 +47,28 @@ template class hwl : public BASE { using this_class = hwl; using reg_t = typename BASE::reg_t; - hwl(feature_config cfg = feature_config{}); + hwl(); virtual ~hwl() = default; protected: - iss::status read_custom_csr(unsigned addr, reg_t& val) override; - iss::status write_custom_csr(unsigned addr, reg_t val) override; + iss::status read_hwl_csr(unsigned addr, reg_t& val); + iss::status write_hwl_csr(unsigned addr, reg_t val); }; template -inline hwl::hwl(feature_config cfg) -: BASE(cfg) { +inline hwl::hwl() +: BASE() { for(unsigned addr = 0x800; addr < 0x803; ++addr) { - this->register_custom_csr_rd(addr); - this->register_custom_csr_wr(addr); + this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_hwl_csr); + this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_hwl_csr); } for(unsigned addr = 0x804; addr < 0x807; ++addr) { - this->register_custom_csr_rd(addr); - this->register_custom_csr_wr(addr); + this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_hwl_csr); + this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_hwl_csr); } } -template inline iss::status iss::arch::hwl::read_custom_csr(unsigned addr, reg_t& val) { +template inline iss::status iss::arch::hwl::read_hwl_csr(unsigned addr, reg_t& val) { switch(addr) { case 0x800: val = this->reg.lpstart0; @@ -92,7 +92,7 @@ template inline iss::status iss::arch::hwl::read_custom_cs return iss::Ok; } -template inline iss::status iss::arch::hwl::write_custom_csr(unsigned addr, reg_t val) { +template inline iss::status iss::arch::hwl::write_hwl_csr(unsigned addr, reg_t val) { switch(addr) { case 0x800: this->reg.lpstart0 = val; 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,21 +51,16 @@ #include #include #include +#include +#include +#include #include #include -#if defined(__GNUC__) -#define likely(x) ::__builtin_expect(!!(x), 1) -#define unlikely(x) ::__builtin_expect(!!(x), 0) -#else -#define likely(x) x -#define unlikely(x) x -#endif - namespace iss { namespace arch { -enum features_e { FEAT_NONE, FEAT_EXT_N = 1, FEAT_DEBUG = 2 }; +enum features_e { FEAT_NONE, FEAT_EXT_N = 1, FEAT_DEBUG = 2, FEAT_AIA = 4 }; enum extension_encoding { A = 1UL << 0, B = 1UL << 1, @@ -141,12 +135,14 @@ enum riscv_csr { sie = 0x104, stvec = 0x105, scounteren = 0x106, + sieh = 0x114, // Supervisor Trap Handling sscratch = 0x140, sepc = 0x141, scause = 0x142, stval = 0x143, sip = 0x144, + siph = 0x154, // Supervisor Protection and Translation satp = 0x180, /* machine-level CSR */ @@ -160,18 +156,24 @@ enum riscv_csr { misa = 0x301, medeleg = 0x302, mideleg = 0x303, + midelegh = 0x313, // AIA defined mie = 0x304, + mieh = 0x314, // AIA defined mtvec = 0x305, mcounteren = 0x306, mtvt = 0x307, // CLIC mstatush = 0x310, medelegh = 0x312, + // AIA defined + mvienh = 0x318, + mviph = 0x319, // Machine Trap Handling mscratch = 0x340, mepc = 0x341, mcause = 0x342, mtval = 0x343, mip = 0x344, + miph = 0x354, // AIA defined mxnti = 0x345, // CLIC mintstatus = 0xFB1, // MRW Current interrupt levels (CLIC) - addr subject to change mintthresh = 0x347, // MRW Interrupt-level threshold (CLIC) - addr subject to change @@ -293,6 +295,8 @@ template struct priv_if { std::function read_csr; std::function write_csr; + std::function get_csr; + std::function set_csr; std::function exec_htif; std::function raise_trap; // trap_id, cause, fault_data std::unordered_map& csr_rd_cb; @@ -305,7 +309,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 +404,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); }; @@ -432,9 +500,9 @@ template struct riscv_hart_co csr_rd_cb[mhartid] = MK_CSR_RD_CB(read_hartid); }; - ~riscv_hart_common() { + virtual ~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())); } } @@ -444,24 +512,32 @@ template struct riscv_hart_co uint64_t fromhost = std::numeric_limits::max(); std::stringstream io_buf; + void enable_disass_output(bool enable) { + if(enable) + this->disass_func = + util::delegate::from(this); + else + this->disass_func = util::delegate(nullptr); + } + 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 +548,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 +572,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 +593,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 +609,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 +620,15 @@ 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 print_disass_output(uint64_t pc, std::string const& string, bool printpc) { + 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(printpc) { + CLOG(INFO, disass) << fmt::format(fmt_str, pc, string, lvl[this->reg.PRIV], (reg_t)this->state.mstatus, this->reg.icount, + this->reg.cycle + cycle_offset); + } else { + CLOG(INFO, disass) << string; + } }; void register_csr(unsigned addr, rd_csr_f f) { csr_rd_cb[addr] = f; } @@ -575,15 +656,12 @@ template struct riscv_hart_co this->csr_rd_cb[dcsr] = MK_CSR_RD_CB(read_debug); } - constexpr reg_t get_irq_mask(size_t mode) { - std::array m = {{ - (std::numeric_limits::max() & ~0xffff) | 0b000100010001, // U mode - (std::numeric_limits::max() & ~0xffff) | 0b001100110011, // S mode - (std::numeric_limits::max() & ~0xffff) | 0, // H mode - (std::numeric_limits::max() & ~0xffff) | 0b101110111011 // M mode - }}; - return m[mode]; - } + std::array mie_mip_mask = {{ + (std::numeric_limits::max() & ~0xffffULL) | 0b000100010001U, // U mode + (std::numeric_limits::max() & ~0xffffULL) | 0b001100110011U, // S mode + (std::numeric_limits::max() & ~0xffffULL) | 0b011101110111U, // H mode + (std::numeric_limits::max() & ~0xffffULL) | 0b111111111111U // M mode + }}; iss::status read_csr(unsigned addr, reg_t& val) { if(addr >= csr.size()) { @@ -854,63 +932,73 @@ 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); }, + .get_csr = [this](unsigned addr) -> reg_t { return csr.at(addr); }, + .set_csr = [this](unsigned addr, reg_t val) -> void { csr.at(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{this->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; } } @@ -924,15 +1012,21 @@ template struct riscv_hart_co void set_next(mem::memory_if mem_if) override { memory = mem_if; }; - void set_irq_num(unsigned i) { mcause_max_irq = std::max(1u << util::ilog2(i), 16u); } + void set_max_irq_num(unsigned i) { mcause_max_irq = std::max(1u << util::ilog2(i), 16u); } + + void set_clint_irq_num(unsigned num) { + assert(num <= traits::XLEN); + clint_custom_irq_mask = std::numeric_limits::max() >> (traits::XLEN - num); + } protected: + 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 @@ -949,7 +1043,7 @@ template struct riscv_hart_co uint64_t get_instr_count() override { return arch.reg.icount; } - uint64_t get_pendig_traps() override { return arch.reg.trap_state; } + uint64_t get_pending_traps() override { return arch.reg.trap_state; } uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } @@ -963,7 +1057,8 @@ template struct riscv_hart_co std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } - riscv_hart_common& arch; + unsigned get_core_id() override { return arch.mhartid_reg; }; + riscv_hart_common& arch; }; friend struct riscv_instrumentation_if; @@ -972,7 +1067,7 @@ template struct riscv_hart_co instrumentation_if* get_instrumentation_if() override { return &instr_if; }; using csr_type = std::array::reg_t, 1ULL << 12>; - csr_type csr; + csr_type csr{0}; std::unordered_map csr_rd_cb; std::unordered_map csr_wr_cb; @@ -980,12 +1075,19 @@ template struct riscv_hart_co reg_t mhartid_reg{0x0}; uint64_t mcycle_csr{0}; uint64_t minstret_csr{0}; + uint64_t mie_csr{0}; + uint64_t mip_csr{0}; + uint64_t mideleg_csr{0}; + uint64_t sie_csr{0}; + uint64_t sip_csr{0}; + uint64_t sideleg_csr{0}; reg_t fault_data; int64_t cycle_offset{0}; int64_t instret_offset{0}; semihosting_cb_t semihosting_cb; - unsigned mcause_max_irq{16U}; + unsigned mcause_max_irq{traits::XLEN}; + uint64_t clint_custom_irq_mask{0xffff}; }; } // namespace arch diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index ef7f96a..de83a35 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,23 +77,18 @@ 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); + void enable_disass(bool enable) { riscv_hart_common::enable_disass_output(enable); } + + 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; uint64_t leave_trap(uint64_t flags) override; - void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } + void set_csr(unsigned addr, reg_t val) { this->csr[addr] = 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); @@ -137,51 +96,87 @@ class riscv_hart_m_p : public riscv_hart_common { iss::status read_ie(unsigned addr, reg_t& val); iss::status write_ie(unsigned addr, reg_t val); iss::status read_ip(unsigned addr, reg_t& val); + iss::status write_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); this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); - this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_plain); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_ip); this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); if(FEAT & FEAT_DEBUG) this->add_debug_csrs(); + if(FEAT & FEAT_AIA && traits::XLEN == 32) { + this->csr_rd_cb[miph] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[miph] = MK_CSR_WR_CB(write_ip); + this->csr_rd_cb[mieh] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mieh] = MK_CSR_WR_CB(write_ie); + } this->rd_func = util::delegate::from(this); this->wr_func = util::delegate::from(this); this->memories.root(*this); 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: { + case traits::CSR: { + if(length != sizeof(reg_t)) + return iss::Err; + auto res = this->read_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; + default: + return iss::Ok; + } + } break; + case traits::RES: { + auto it = atomic_reservation.find(addr); + if(it != atomic_reservation.end() && it->second != 0) { + memset(data, 0xff, length); + atomic_reservation.erase(addr); + } else + memset(data, 0, length); + } break; + 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); // issue trap 0 + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; return iss::Err; } try { @@ -190,7 +185,7 @@ iss::status riscv_hart_m_p::read(const address_type type, co this->fault_data = addr; return iss::Err; } - auto res = this->memory.rd_mem(access, addr, length, data); + 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; @@ -204,36 +199,6 @@ iss::status riscv_hart_m_p::read(const address_type type, co return iss::Err; } } break; - case traits::CSR: { - if(length != sizeof(reg_t)) - return iss::Err; - auto res = this->read_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; - } - } break; - case traits::RES: { - auto it = atomic_reservation.find(addr); - if(it != atomic_reservation.end() && it->second != 0) { - memset(data, 0xff, length); - atomic_reservation.erase(addr); - } else - memset(data, 0, length); - } break; - default: - return iss::Err; // assert("Not supported"); } return iss::Ok; } catch(trap_access& ta) { @@ -245,40 +210,63 @@ 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: { + 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; + 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) + if(access && 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 { @@ -288,7 +276,7 @@ iss::status riscv_hart_m_p::write(const address_type type, c 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; @@ -300,31 +288,6 @@ iss::status riscv_hart_m_p::write(const address_type type, c 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) { @@ -336,58 +299,80 @@ 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) { - auto mask = riscv_hart_common::get_irq_mask(3); - val = this->csr[mie] & mask; +template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[3] & ~0x777ULL; // clear H, S & U mode bits + if(unlikely(addr == mieh)) + val = (this->mie_csr & mask) >> 32; + else + val = this->mie_csr & mask; return iss::Ok; } -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); +template iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t val) { + uint64_t lval = val; + if(addr == mieh) { + lval <<= 32; + lval |= static_cast(this->mie_csr); + } else if(sizeof(reg_t) == 4) + lval |= this->mie_csr & ~static_cast(std::numeric_limits::max()); + // generate mask from allowed writable bits, the number of custom interrupts and the available ie bits + auto mask = this->mie_mip_mask[3] & this->clint_custom_irq_mask & ~0x777ULL; // clear H, S & U mode bits + this->mie_csr = (this->mie_csr & ~mask) | (lval & mask); check_interrupt(); return iss::Ok; } -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; +template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[3] & ~0x777ULL; // clear H, S & U mode bits + if(unlikely(addr == miph)) + val = (this->mip_csr & mask) >> 32; + else + val = this->mip_csr & mask; return iss::Ok; } -template inline void riscv_hart_m_p::reset(uint64_t address) { +template iss::status riscv_hart_m_p::write_ip(unsigned addr, reg_t val) { + uint64_t lval = val; + if(addr == miph) { + lval <<= 32; + lval |= static_cast(this->mip_csr); + } else if(sizeof(reg_t) == 4) + lval |= this->mip_csr & ~static_cast(std::numeric_limits::max()); + // generate mask from allowed writable bits, the number of custom interrupts and the available ie bits + auto mask = this->mie_mip_mask[3] & this->clint_custom_irq_mask & ~0x777ULL; // clear H, S & U mode bits + this->mip_csr = (this->mip_csr & ~mask) | (lval & mask); + check_interrupt(); + return iss::Ok; +} + +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]; + auto ena_irq = this->mip_csr & this->mie_csr; - 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; - - if(enabled_interrupts != 0) { + this->reg.pending_trap = 0; + if(enabled_interrupts) { int res = 0; while((enabled_interrupts & 1) == 0) { enabled_interrupts >>= 1; @@ -397,8 +382,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 +422,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 +436,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 "; - + this->disass_output(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 +474,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 +491,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) { + auto irq_str = cause < this->irq_str.size() ? this->irq_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", irq_str, cause, buffer.data())); + } else { + auto irq_str = cause < this->trap_str.size() ? this->trap_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Trap with cause '{}' ({}) occurred at address {}", irq_str, 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"; + this->disass_output("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..1e3f898 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) { + 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); - this->state.mstatus = new_val; - } - - 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); - 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,17 +90,17 @@ 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); + void enable_disass(bool enable) { riscv_hart_common::enable_disass_output(enable); } + + 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; uint64_t leave_trap(uint64_t flags) override; void wait_until(uint64_t flags) override; - void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } + void set_csr(unsigned addr, reg_t val) { this->csr[addr] = val; } protected: using mem_read_f = iss::status(iss::phys_addr_t addr, unsigned, uint8_t* const); @@ -164,20 +115,25 @@ class riscv_hart_msu_vp : public riscv_hart_common { iss::status read_ie(unsigned addr, reg_t& val); iss::status write_ie(unsigned addr, reg_t val); iss::status read_ip(unsigned addr, reg_t& val); + iss::status write_ip(unsigned addr, reg_t val); iss::status write_ideleg(unsigned addr, reg_t val); iss::status write_edeleg(unsigned addr, uint32_t val); iss::status write_edeleg(unsigned addr, uint64_t val); 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}}; @@ -195,9 +151,9 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() this->csr_rd_cb[stvec] = MK_CSR_RD_CB(read_tvec); this->csr_wr_cb[stvec] = MK_CSR_WR_CB(write_plain); this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); - this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_plain); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_ip); this->csr_rd_cb[sip] = MK_CSR_RD_CB(read_ip); - this->csr_wr_cb[sip] = MK_CSR_WR_CB(write_plain); + this->csr_wr_cb[sip] = MK_CSR_WR_CB(write_ip); this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); this->csr_rd_cb[sie] = MK_CSR_RD_CB(read_ie); @@ -208,7 +164,7 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() this->csr_wr_cb[ucause] = MK_CSR_WR_CB(write_cause); this->csr_rd_cb[utvec] = MK_CSR_RD_CB(read_tvec); this->csr_rd_cb[uip] = MK_CSR_RD_CB(read_ip); - this->csr_wr_cb[uip] = MK_CSR_WR_CB(write_plain); + this->csr_wr_cb[uip] = MK_CSR_WR_CB(write_ip); this->csr_rd_cb[uie] = MK_CSR_RD_CB(read_ie); this->csr_wr_cb[uie] = MK_CSR_WR_CB(write_ie); this->csr[misa] |= extension_encoding::N; @@ -230,6 +186,15 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() if(FEAT & FEAT_DEBUG) this->add_debug_csrs(); + if(FEAT & FEAT_AIA && traits::XLEN == 32) { + this->csr_rd_cb[miph] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[miph] = MK_CSR_WR_CB(write_ip); + this->csr_rd_cb[mieh] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mieh] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[midelegh] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[midelegh] = MK_CSR_WR_CB(write_ideleg); + } + this->rd_func = util::delegate::from(this); this->wr_func = util::delegate::from(this); this->set_next(mmu.get_mem_if()); @@ -238,49 +203,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 +251,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 +291,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 +356,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,78 +394,159 @@ 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) { - val = this->csr[mie]; - if(addr < mie) - val &= this->csr[mideleg]; - if(addr < sie) - val &= this->csr[sideleg]; +template iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + switch(addr) { + case mie: + case mieh: + if(unlikely(addr == mieh)) + val = (this->mie_csr & mask) >> 32; + else + val = this->mie_csr & mask; + break; + case sie: + case sieh: + if(unlikely(addr == sieh)) + val = (this->sie_csr & mask) >> 32; + else + val = this->sie_csr & mask; + break; + } return iss::Ok; } -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); +template iss::status riscv_hart_msu_vp::write_ie(unsigned addr, reg_t val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + uint64_t lval = val; + switch(addr) { + case mieh: + lval <<= 32; + lval |= static_cast(this->mie_csr); // add the lower part of mie_csr + this->mie_csr = (this->mie_csr & ~mask) | (lval & mask); + break; + case mie: + if(sizeof(reg_t) == 4) // add the upper part of mie_csr + lval |= this->mie_csr & ~static_cast(std::numeric_limits::max()); + this->mie_csr = (this->mie_csr & ~mask) | (lval & mask); + break; + case sieh: + lval <<= 32; + lval |= static_cast(this->mie_csr); // add the lower part of mie_csr + this->sie_csr = (this->sie_csr & ~mask) | (lval & mask); + break; + case sie: + if(sizeof(reg_t) == 4) // add the upper part of mie_csr + lval |= this->mie_csr & ~static_cast(std::numeric_limits::max()); + this->sie_csr = (this->sie_csr & ~mask) | (lval & mask); + break; + } check_interrupt(); return iss::Ok; } -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]; - if(addr < sip) - val &= this->csr[sideleg]; +template iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + switch(addr) { + case mip: + case miph: + if(unlikely(addr == mieh)) + val = (this->mip_csr & mask) >> 32; + else + val = this->mip_csr & mask; + break; + case sip: + case siph: + if(unlikely(addr == sieh)) + val = (this->sip_csr & mask) >> 32; + else + val = this->sip_csr & mask; + break; + } + return iss::Ok; +} + +template iss::status riscv_hart_msu_vp::write_ip(unsigned addr, reg_t val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + uint64_t lval = val; + switch(addr) { + case miph: + lval <<= 32; + lval |= static_cast(this->mip_csr); // add the lower part of mip_csr + this->mip_csr = (this->mip_csr & ~mask) | (lval & mask); + break; + case mip: + if(sizeof(reg_t) == 4) // add the upper part of mip_csr + lval |= this->mip_csr & ~static_cast(std::numeric_limits::max()); + this->mip_csr = (this->mip_csr & ~mask) | (lval & mask); + break; + case siph: + lval <<= 32; + lval |= static_cast(this->sip_csr); // add the lower part of sip_csr + this->sip_csr = (this->sip_csr & ~mask) | (lval & mask); + break; + case sip: + if(sizeof(reg_t) == 4) // add the upper part of sip_csr + lval |= this->sip_csr & ~static_cast(std::numeric_limits::max()); + this->sip_csr = (this->sip_csr & ~mask) | (lval & mask); + break; + } + check_interrupt(); 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,25 +555,24 @@ 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]; + auto ip = this->mip_csr; + auto ie = this->mie_csr; auto ideleg = this->csr[mideleg]; // Multiple simultaneous interrupts and traps at the same privilege level are // handled in the following decreasing priority order: @@ -536,7 +583,7 @@ template void riscv_hart_msu_v bool mie = this->state.mstatus.MIE; auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie); auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0; - + this->reg.pending_trap = 0; if(enabled_interrupts == 0) { auto sie = this->state.mstatus.SIE; auto s_enabled = this->reg.PRIV < PRIV_S || (this->reg.PRIV == PRIV_S && sie); @@ -550,8 +597,7 @@ 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 tval) { // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // calculate and write mcause val if(flags == std::numeric_limits::max()) @@ -579,12 +625,11 @@ uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint6 */ switch(cause) { case traits::RV_CAUSE_MISALIGNED_FETCH: - this->csr[mtval] = static_cast(instr); + this->csr[mtval] = static_cast(tval); break; - case traits::RV_CAUSE_ILLEGAL_INSTRUCTION: #ifdef MTVAL_ILLEGAL_INFORMATIVE - this->csr[utval | (new_priv << 8)] = (!this->has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff; + this->csr[utval | (new_priv << 8)] = (!this->has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff; #endif break; case traits::RV_CAUSE_BREAKPOINT: @@ -599,9 +644,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 +658,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 "; - + this->disass_output(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 +720,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 +734,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) { + auto irq_str = cause < this->irq_str.size() ? this->irq_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", irq_str, cause, buffer.data())); + } else { + auto irq_str = cause < this->trap_str.size() ? this->trap_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Trap with cause '{}' ({}) occurred at address {}", irq_str, 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 +782,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]; + this->disass_output( + 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..dbbeb35 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -39,9 +39,11 @@ #include "iss/vm_if.h" #include "iss/vm_types.h" #include "riscv_hart_common.h" +#include "util/ities.h" #include "util/logging.h" #include #include +#include #include #include #include @@ -56,74 +58,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,24 +81,22 @@ 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); + void enable_disass(bool enable) { riscv_hart_common::enable_disass_output(enable); } + + 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; uint64_t leave_trap(uint64_t flags) override; void wait_until(uint64_t flags) override; - void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } + void set_csr(unsigned addr, reg_t val) { this->csr[addr] = 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); @@ -158,19 +104,22 @@ class riscv_hart_mu_p : public riscv_hart_common { iss::status read_ie(unsigned addr, reg_t& val); iss::status write_ie(unsigned addr, reg_t val); iss::status read_ip(unsigned addr, reg_t& val); + iss::status write_ip(unsigned addr, reg_t val); + iss::status write_ideleg(unsigned addr, reg_t val); + iss::status write_edeleg(unsigned addr, uint32_t val); + iss::status write_edeleg(unsigned addr, uint64_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); - this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_plain); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_ip); this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); this->csr_rd_cb[mcounteren] = MK_CSR_RD_CB(read_null); @@ -187,17 +136,32 @@ riscv_hart_mu_p::riscv_hart_mu_p() this->csr_wr_cb[ustatus] = MK_CSR_WR_CB(write_status); this->csr_rd_cb[ucause] = MK_CSR_RD_CB(read_cause); this->csr_wr_cb[ucause] = MK_CSR_WR_CB(write_cause); - this->csr_rd_cb[utvec] = MK_CSR_RD_CB(read_plain); this->csr_rd_cb[utvec] = MK_CSR_RD_CB(read_tvec); + this->csr_wr_cb[utvec] = MK_CSR_WR_CB(write_plain); this->csr_rd_cb[uscratch] = MK_CSR_RD_CB(read_plain); this->csr_wr_cb[uscratch] = MK_CSR_WR_CB(write_plain); this->csr_rd_cb[utval] = MK_CSR_RD_CB(read_plain); this->csr_wr_cb[utval] = MK_CSR_WR_CB(write_plain); this->csr[misa] |= extension_encoding::N; + this->csr_rd_cb[mideleg] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mideleg] = MK_CSR_WR_CB(write_ideleg); + this->csr_rd_cb[medeleg] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[medeleg] = MK_CSR_WR_CB(write_edeleg); } if(FEAT & FEAT_DEBUG) this->add_debug_csrs(); + if(FEAT & FEAT_AIA && traits::XLEN == 32) { + this->csr_rd_cb[miph] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[miph] = MK_CSR_WR_CB(write_ip); + this->csr_rd_cb[mieh] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mieh] = MK_CSR_WR_CB(write_ie); + if(FEAT & FEAT_EXT_N) { + this->csr_rd_cb[midelegh] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[midelegh] = MK_CSR_WR_CB(write_ideleg); + } + } + this->rd_func = util::delegate::from(this); this->wr_func = util::delegate::from(this); this->memories.root(*this); @@ -205,27 +169,56 @@ 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: { + case traits::CSR: { + if(length != sizeof(reg_t)) + return iss::Err; + auto res = this->read_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; + default: + return iss::Ok; + } + } + case traits::RES: { + auto it = atomic_reservation.find(addr); + if(it != atomic_reservation.end() && it->second != 0) { + memset(data, 0xff, length); + atomic_reservation.erase(addr); + } else + memset(data, 0, length); + } break; + 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); // issue trap 0 + this->reg.trap_state = (1UL << 31) | traits::RV_CAUSE_MISALIGNED_FETCH << 16; return iss::Err; } try { @@ -234,7 +227,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, c this->fault_data = addr; return iss::Err; } - auto res = this->memory.rd_mem(access, addr, length, data); + 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; @@ -248,36 +241,6 @@ iss::status riscv_hart_mu_p::read(const address_type type, c return iss::Err; } } break; - case traits::CSR: { - if(length != sizeof(reg_t)) - return iss::Err; - auto res = this->read_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: { - auto it = atomic_reservation.find(addr); - if(it != atomic_reservation.end() && it->second != 0) { - memset(data, 0xff, length); - atomic_reservation.erase(addr); - } else - memset(data, 0, length); - } break; - default: - return iss::Err; // assert("Not supported"); } return iss::Ok; } catch(trap_access& ta) { @@ -289,40 +252,63 @@ 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; + 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 +318,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 +330,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,58 +341,120 @@ 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) { - auto mask = riscv_hart_common::get_irq_mask((addr >> 8) & 0x3); - val = this->csr[mie] & mask; +template iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + if(unlikely(addr == mieh)) + val = (this->mie_csr & mask) >> 32; + else + val = this->mie_csr & mask; return iss::Ok; } -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); +template iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t val) { + uint64_t lval = val; + if(addr == mieh) { + lval <<= 32; + lval |= static_cast(this->mie_csr); + } else if(sizeof(reg_t) == 4) + lval |= this->mie_csr & ~static_cast(std::numeric_limits::max()); + // generate mask from allowed writable bits, the number of custom interrupts and the available ie bits + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3] & this->clint_custom_irq_mask; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + this->mie_csr = (this->mie_csr & ~mask) | (lval & mask); check_interrupt(); return iss::Ok; } -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; +template iss::status riscv_hart_mu_p::read_ip(unsigned addr, reg_t& val) { + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3]; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + if(unlikely(addr == miph)) + val = (this->mip_csr & mask) >> 32; + else + val = this->mip_csr & mask; return iss::Ok; } -template inline void riscv_hart_mu_p::reset(uint64_t address) { +template iss::status riscv_hart_mu_p::write_ip(unsigned addr, reg_t val) { + uint64_t lval = val; + if(addr == mieh) { + lval <<= 32; + lval |= static_cast(this->mip_csr); + } else if(sizeof(reg_t) == 4) + lval |= this->mip_csr & ~static_cast(std::numeric_limits::max()); + // generate mask from allowed writable bits, the number of custom interrupts and the available ie bits + auto mask = this->mie_mip_mask[(addr >> 8) & 0x3] & this->clint_custom_irq_mask; + if(FEAT & FEAT_EXT_N) + mask &= ~0x666ULL; // clear H & S mode bits + else + mask &= ~0x777ULL; // clear H, S & U mode bits + this->mip_csr = (this->mip_csr & ~mask) | (lval & mask); + check_interrupt(); + return iss::Ok; +} + +template iss::status riscv_hart_mu_p::write_ideleg(unsigned addr, reg_t val) { + uint64_t lval = val; + if(addr == midelegh) + lval <<= 32; + // only U mode interrupts can be delegated + auto mask = 0xffff'0111ul; + this->mideleg_csr = (this->mideleg_csr & ~mask) | (lval & mask); + return iss::Ok; +} + +template iss::status riscv_hart_mu_p::write_edeleg(unsigned addr, uint32_t val) { + // we mask according to privilege spec: bit 3 (break), bit 10 (reserved), bit 11 (Ecall from M) bit 14 (reserved) + uint32_t mask = 0b0000'0000'0000'0000'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_mu_p::write_edeleg(unsigned addr, uint64_t val) { + // we mask according to privilege spec: bit 3 (break), bit 10 (reserved), bit 11 (Ecall from M) bit 14 (reserved) + uint64_t mask = 0b0000'0000'0000'0000'1011'0011'1111'0111; + this->csr[arch::riscv_csr::medeleg] = (this->csr[arch::riscv_csr::medeleg] & ~mask) | (val & mask); + return iss::Ok; +} + +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: // external interrupts, software interrupts, timer interrupts, then finally // any synchronous traps. - auto ena_irq = this->csr[mip] & this->csr[mie]; + auto ena_irq = this->mip_csr & this->mie_csr; - 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; - + this->reg.pending_trap = 0; if(enabled_interrupts != 0) { int res = 0; while((enabled_interrupts & 1) == 0) { @@ -442,8 +465,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()) @@ -470,7 +492,7 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ break; case traits::RV_CAUSE_ILLEGAL_INSTRUCTION: #ifdef MTVAL_ILLEGAL_INFORMATIVE - this->csr[utval | (new_priv << 8)] = (!this->has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff; + this->csr[utval | (new_priv << 8)] = (!this->has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff; #endif break; case traits::RV_CAUSE_BREAKPOINT: @@ -485,9 +507,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 +523,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 "; - + this->disass_output(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 +555,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 +575,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 +589,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) { + auto irq_str = cause < this->irq_str.size() ? this->irq_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Interrupt with cause '{}' ({}) occurred at address {}", irq_str, cause, buffer.data())); + } else { + auto irq_str = cause < this->trap_str.size() ? this->trap_str.at(cause) : "Unknown"; + this->disass_output(fmt::format("Trap with cause '{}' ({}) occurred at address {}", irq_str, 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]; + this->disass_output( + 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..c4a6646 100644 --- a/src/iss/arch/rv32gc.h +++ b/src/iss/arch/rv32gc.h @@ -64,6 +64,8 @@ struct rv32gc: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV32GC_regs { uint32_t X0 = 0; uint32_t X1 = 0; @@ -160,8 +162,6 @@ struct rv32gc: public arch_if { }; -struct rv32gc; - template <> struct traits { constexpr static char const* const core_type = "RV32GC"; @@ -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..78b791a 100644 --- a/src/iss/arch/rv32gcv.h +++ b/src/iss/arch/rv32gcv.h @@ -64,6 +64,8 @@ struct rv32gcv: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV32GCV_regs { uint32_t X0 = 0; uint32_t X1 = 0; @@ -197,8 +199,6 @@ struct rv32gcv: public arch_if { }; -struct rv32gcv; - template <> struct traits { constexpr static char const* const core_type = "RV32GCV"; @@ -324,16 +324,16 @@ 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, FP_SEW_MIN=32ULL, FP_SEW_MAX=64ULL, VSTART_ADDR=8ULL, VXSAT_ADDR=9ULL, VXRM_ADDR=10ULL, VCSR_ADDR=15ULL, VL_ADDR=3104ULL, VTYPE_ADDR=3105ULL, - VLENB_ADDR=3106ULL, MISA_VAL=1073746221ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL + VLENB_ADDR=3106ULL, MISA_VAL=1075843373ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL }; @@ -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..0c3d7bb 100644 --- a/src/iss/arch/rv32i.h +++ b/src/iss/arch/rv32i.h @@ -64,6 +64,8 @@ struct rv32i: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV32I_regs { uint32_t X0 = 0; uint32_t X1 = 0; @@ -127,8 +129,6 @@ struct rv32i: public arch_if { }; -struct rv32i; - template <> struct traits { constexpr static char const* const core_type = "RV32I"; @@ -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..f0a500c 100644 --- a/src/iss/arch/rv32imac.h +++ b/src/iss/arch/rv32imac.h @@ -64,6 +64,8 @@ struct rv32imac: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV32IMAC_regs { uint32_t X0 = 0; uint32_t X1 = 0; @@ -127,8 +129,6 @@ struct rv32imac: public arch_if { }; -struct rv32imac; - template <> struct traits { constexpr static char const* const core_type = "RV32IMAC"; @@ -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..aca78ae 100644 --- a/src/iss/arch/rv64gc.h +++ b/src/iss/arch/rv64gc.h @@ -64,6 +64,8 @@ struct rv64gc: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV64GC_regs { uint64_t X0 = 0; uint64_t X1 = 0; @@ -160,8 +162,6 @@ struct rv64gc: public arch_if { }; -struct rv64gc; - template <> struct traits { constexpr static char const* const core_type = "RV64GC"; @@ -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..2be8f96 100644 --- a/src/iss/arch/rv64gcv.h +++ b/src/iss/arch/rv64gcv.h @@ -64,6 +64,8 @@ struct rv64gcv: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV64GCV_regs { uint64_t X0 = 0; uint64_t X1 = 0; @@ -197,8 +199,6 @@ struct rv64gcv: public arch_if { }; -struct rv64gcv; - template <> struct traits { constexpr static char const* const core_type = "RV64GCV"; @@ -324,16 +324,16 @@ 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, FP_SEW_MIN=32ULL, FP_SEW_MAX=64ULL, VSTART_ADDR=8ULL, VXSAT_ADDR=9ULL, VXRM_ADDR=10ULL, VCSR_ADDR=15ULL, VL_ADDR=3104ULL, VTYPE_ADDR=3105ULL, - VLENB_ADDR=3106ULL, MISA_VAL=9223372036854780205ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL + VLENB_ADDR=3106ULL, MISA_VAL=9223372036856877357ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL }; @@ -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..cf54cb3 100644 --- a/src/iss/arch/rv64i.h +++ b/src/iss/arch/rv64i.h @@ -64,6 +64,8 @@ struct rv64i: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct RV64I_regs { uint64_t X0 = 0; uint64_t X1 = 0; @@ -127,8 +129,6 @@ struct rv64i: public arch_if { }; -struct rv64i; - template <> struct traits { constexpr static char const* const core_type = "RV64I"; @@ -254,12 +254,12 @@ 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, + fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MISA_VAL=9223372036854776064ULL, 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/rv32imc.cpp b/src/iss/arch/rv64imac.cpp similarity index 80% rename from src/iss/arch/rv32imc.cpp rename to src/iss/arch/rv64imac.cpp index 99aa057..ce78811 100644 --- a/src/iss/arch/rv32imc.cpp +++ b/src/iss/arch/rv64imac.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2017 - 2020 MINRES Technologies GmbH + * Copyright (C) 2024 MINRES Technologies GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ *******************************************************************************/ // clang-format off -#include "rv32imc.h" +#include "rv64imac.h" #include "util/ities.h" #include #include @@ -40,18 +40,18 @@ 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; +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; +rv64imac::rv64imac() = default; -rv32imc::~rv32imc() = default; +rv64imac::~rv64imac() = 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) +void rv64imac::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; @@ -60,11 +60,11 @@ void rv32imc::reset(uint64_t address) { reg.icount=0; } -uint8_t *rv32imc::get_regs_base_ptr() { +uint8_t *rv64imac::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); +rv64imac::phys_addr_t rv64imac::virt2phys(const iss::addr_t &addr) { + return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); } // clang-format on diff --git a/src/iss/arch/rv64imac.h b/src/iss/arch/rv64imac.h new file mode 100644 index 0000000..05bf15a --- /dev/null +++ b/src/iss/arch/rv64imac.h @@ -0,0 +1,531 @@ +/******************************************************************************* + * Copyright (C) 2024 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 _RV64IMAC_H_ +#define _RV64IMAC_H_ +// clang-format off +#include +#include +#include +#include + +namespace iss { +namespace arch { + +struct rv64imac: public arch_if { + + using reg_t = uint64_t; + + using virt_addr_t = iss::virt_addr_t; + + using phys_addr_t = iss::phys_addr_t; + + rv64imac(); + ~rv64imac(); + + void reset(uint64_t address=0) override; + + uint8_t* get_regs_base_ptr() override; + + 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; } + + virtual void enable_disass(bool) = 0; + + struct RV64IMAC_regs { + uint64_t X0 = 0; + uint64_t X1 = 0; + uint64_t X2 = 0; + uint64_t X3 = 0; + uint64_t X4 = 0; + uint64_t X5 = 0; + uint64_t X6 = 0; + uint64_t X7 = 0; + uint64_t X8 = 0; + uint64_t X9 = 0; + uint64_t X10 = 0; + uint64_t X11 = 0; + uint64_t X12 = 0; + uint64_t X13 = 0; + uint64_t X14 = 0; + uint64_t X15 = 0; + uint64_t X16 = 0; + uint64_t X17 = 0; + uint64_t X18 = 0; + uint64_t X19 = 0; + uint64_t X20 = 0; + uint64_t X21 = 0; + uint64_t X22 = 0; + uint64_t X23 = 0; + uint64_t X24 = 0; + uint64_t X25 = 0; + uint64_t X26 = 0; + uint64_t X27 = 0; + uint64_t X28 = 0; + uint64_t X29 = 0; + uint64_t X30 = 0; + uint64_t X31 = 0; + uint64_t PC = 0; + uint64_t NEXT_PC = 0; + uint8_t PRIV = 0; + uint64_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; + + std::array addr_mode; + + uint64_t interrupt_sim=0; + + uint32_t get_fcsr(){return 0;} + void set_fcsr(uint32_t val){} + + uint32_t get_vstart(){return 0;} + void set_vstart(uint32_t val){} + uint32_t get_vl(){return 0;} + uint32_t get_vtype(){return 0;} + uint32_t get_vxsat(){return 0;} + void set_vxsat(uint32_t val){} + uint32_t get_vxrm(){return 0;} + void set_vxrm(uint32_t val){} + +}; + +template <> struct traits { + + constexpr static char const* const core_type = "RV64IMAC"; + + 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 { + RV_CSR_FFLAGS=1ULL, RV_CSR_FRM=2ULL, RV_CSR_FCSR=3ULL, RV_CSR_UTVT=7ULL, + RV_CSR_VSTART=8ULL, RV_CSR_VXSAT=9ULL, RV_CSR_VXRM=10ULL, RV_CSR_VCSR=15ULL, + RV_CSR_SEED=21ULL, RV_CSR_UNXTI=69ULL, RV_CSR_UINTSTATUS=70ULL, RV_CSR_USCRATCHCSW=72ULL, + RV_CSR_USCRATCHCSWL=73ULL, RV_CSR_SSTATUS=256ULL, RV_CSR_SEDELEG=258ULL, RV_CSR_SIDELEG=259ULL, + RV_CSR_SIE=260ULL, RV_CSR_STVEC=261ULL, RV_CSR_SCOUNTEREN=262ULL, RV_CSR_STVT=263ULL, + RV_CSR_SENVCFG=266ULL, RV_CSR_SSTATEEN0=268ULL, RV_CSR_SSTATEEN1=269ULL, RV_CSR_SSTATEEN2=270ULL, + RV_CSR_SSTATEEN3=271ULL, RV_CSR_SSCRATCH=320ULL, RV_CSR_SEPC=321ULL, RV_CSR_SCAUSE=322ULL, + RV_CSR_STVAL=323ULL, RV_CSR_SIP=324ULL, RV_CSR_SNXTI=325ULL, RV_CSR_SINTSTATUS=326ULL, + RV_CSR_SSCRATCHCSW=328ULL, RV_CSR_SSCRATCHCSWL=329ULL, RV_CSR_STIMECMP=333ULL, RV_CSR_STIMECMPH=349ULL, + RV_CSR_SATP=384ULL, RV_CSR_VSSTATUS=512ULL, RV_CSR_VSIE=516ULL, RV_CSR_VSTVEC=517ULL, + RV_CSR_VSSCRATCH=576ULL, RV_CSR_VSEPC=577ULL, RV_CSR_VSCAUSE=578ULL, RV_CSR_VSTVAL=579ULL, + RV_CSR_VSIP=580ULL, RV_CSR_VSTIMECMP=589ULL, RV_CSR_VSTIMECMPH=605ULL, RV_CSR_VSATP=640ULL, + RV_CSR_MSTATUS=768ULL, RV_CSR_MISA=769ULL, RV_CSR_MEDELEG=770ULL, RV_CSR_MIDELEG=771ULL, + RV_CSR_MIE=772ULL, RV_CSR_MTVEC=773ULL, RV_CSR_MCOUNTEREN=774ULL, RV_CSR_MTVT=775ULL, + RV_CSR_MENVCFG=778ULL, RV_CSR_MSTATEEN0=780ULL, RV_CSR_MSTATEEN1=781ULL, RV_CSR_MSTATEEN2=782ULL, + RV_CSR_MSTATEEN3=783ULL, RV_CSR_MSTATUSH=784ULL, RV_CSR_MENVCFGH=794ULL, RV_CSR_MSTATEEN0H=796ULL, + RV_CSR_MSTATEEN1H=797ULL, RV_CSR_MSTATEEN2H=798ULL, RV_CSR_MSTATEEN3H=799ULL, RV_CSR_MCOUNTINHIBIT=800ULL, + RV_CSR_MHPMEVENT3=803ULL, RV_CSR_MHPMEVENT4=804ULL, RV_CSR_MHPMEVENT5=805ULL, RV_CSR_MHPMEVENT6=806ULL, + RV_CSR_MHPMEVENT7=807ULL, RV_CSR_MHPMEVENT8=808ULL, RV_CSR_MHPMEVENT9=809ULL, RV_CSR_MHPMEVENT10=810ULL, + RV_CSR_MHPMEVENT11=811ULL, RV_CSR_MHPMEVENT12=812ULL, RV_CSR_MHPMEVENT13=813ULL, RV_CSR_MHPMEVENT14=814ULL, + RV_CSR_MHPMEVENT15=815ULL, RV_CSR_MHPMEVENT16=816ULL, RV_CSR_MHPMEVENT17=817ULL, RV_CSR_MHPMEVENT18=818ULL, + RV_CSR_MHPMEVENT19=819ULL, RV_CSR_MHPMEVENT20=820ULL, RV_CSR_MHPMEVENT21=821ULL, RV_CSR_MHPMEVENT22=822ULL, + RV_CSR_MHPMEVENT23=823ULL, RV_CSR_MHPMEVENT24=824ULL, RV_CSR_MHPMEVENT25=825ULL, RV_CSR_MHPMEVENT26=826ULL, + RV_CSR_MHPMEVENT27=827ULL, RV_CSR_MHPMEVENT28=828ULL, RV_CSR_MHPMEVENT29=829ULL, RV_CSR_MHPMEVENT30=830ULL, + RV_CSR_MHPMEVENT31=831ULL, RV_CSR_MSCRATCH=832ULL, RV_CSR_MEPC=833ULL, RV_CSR_MCAUSE=834ULL, + RV_CSR_MTVAL=835ULL, RV_CSR_MIP=836ULL, RV_CSR_MNXTI=837ULL, RV_CSR_MINTSTATUS=838ULL, + RV_CSR_MSCRATCHCSW=840ULL, RV_CSR_MSCRATCHCSWL=841ULL, RV_CSR_MTINST=842ULL, RV_CSR_MTVAL2=843ULL, + RV_CSR_PMPCFG0=928ULL, RV_CSR_PMPCFG1=929ULL, RV_CSR_PMPCFG2=930ULL, RV_CSR_PMPCFG3=931ULL, + RV_CSR_PMPCFG4=932ULL, RV_CSR_PMPCFG5=933ULL, RV_CSR_PMPCFG6=934ULL, RV_CSR_PMPCFG7=935ULL, + RV_CSR_PMPCFG8=936ULL, RV_CSR_PMPCFG9=937ULL, RV_CSR_PMPCFG10=938ULL, RV_CSR_PMPCFG11=939ULL, + RV_CSR_PMPCFG12=940ULL, RV_CSR_PMPCFG13=941ULL, RV_CSR_PMPCFG14=942ULL, RV_CSR_PMPCFG15=943ULL, + RV_CSR_PMPADDR0=944ULL, RV_CSR_PMPADDR1=945ULL, RV_CSR_PMPADDR2=946ULL, RV_CSR_PMPADDR3=947ULL, + RV_CSR_PMPADDR4=948ULL, RV_CSR_PMPADDR5=949ULL, RV_CSR_PMPADDR6=950ULL, RV_CSR_PMPADDR7=951ULL, + RV_CSR_PMPADDR8=952ULL, RV_CSR_PMPADDR9=953ULL, RV_CSR_PMPADDR10=954ULL, RV_CSR_PMPADDR11=955ULL, + RV_CSR_PMPADDR12=956ULL, RV_CSR_PMPADDR13=957ULL, RV_CSR_PMPADDR14=958ULL, RV_CSR_PMPADDR15=959ULL, + RV_CSR_PMPADDR16=960ULL, RV_CSR_PMPADDR17=961ULL, RV_CSR_PMPADDR18=962ULL, RV_CSR_PMPADDR19=963ULL, + RV_CSR_PMPADDR20=964ULL, RV_CSR_PMPADDR21=965ULL, RV_CSR_PMPADDR22=966ULL, RV_CSR_PMPADDR23=967ULL, + RV_CSR_PMPADDR24=968ULL, RV_CSR_PMPADDR25=969ULL, RV_CSR_PMPADDR26=970ULL, RV_CSR_PMPADDR27=971ULL, + RV_CSR_PMPADDR28=972ULL, RV_CSR_PMPADDR29=973ULL, RV_CSR_PMPADDR30=974ULL, RV_CSR_PMPADDR31=975ULL, + RV_CSR_PMPADDR32=976ULL, RV_CSR_PMPADDR33=977ULL, RV_CSR_PMPADDR34=978ULL, RV_CSR_PMPADDR35=979ULL, + RV_CSR_PMPADDR36=980ULL, RV_CSR_PMPADDR37=981ULL, RV_CSR_PMPADDR38=982ULL, RV_CSR_PMPADDR39=983ULL, + RV_CSR_PMPADDR40=984ULL, RV_CSR_PMPADDR41=985ULL, RV_CSR_PMPADDR42=986ULL, RV_CSR_PMPADDR43=987ULL, + RV_CSR_PMPADDR44=988ULL, RV_CSR_PMPADDR45=989ULL, RV_CSR_PMPADDR46=990ULL, RV_CSR_PMPADDR47=991ULL, + RV_CSR_PMPADDR48=992ULL, RV_CSR_PMPADDR49=993ULL, RV_CSR_PMPADDR50=994ULL, RV_CSR_PMPADDR51=995ULL, + RV_CSR_PMPADDR52=996ULL, RV_CSR_PMPADDR53=997ULL, RV_CSR_PMPADDR54=998ULL, RV_CSR_PMPADDR55=999ULL, + RV_CSR_PMPADDR56=1000ULL, RV_CSR_PMPADDR57=1001ULL, RV_CSR_PMPADDR58=1002ULL, RV_CSR_PMPADDR59=1003ULL, + RV_CSR_PMPADDR60=1004ULL, RV_CSR_PMPADDR61=1005ULL, RV_CSR_PMPADDR62=1006ULL, RV_CSR_PMPADDR63=1007ULL, + RV_CSR_SCONTEXT=1448ULL, RV_CSR_HSTATUS=1536ULL, RV_CSR_HEDELEG=1538ULL, RV_CSR_HIDELEG=1539ULL, + RV_CSR_HIE=1540ULL, RV_CSR_HTIMEDELTA=1541ULL, RV_CSR_HCOUNTEREN=1542ULL, RV_CSR_HGEIE=1543ULL, + RV_CSR_HENVCFG=1546ULL, RV_CSR_HSTATEEN0=1548ULL, RV_CSR_HSTATEEN1=1549ULL, RV_CSR_HSTATEEN2=1550ULL, + RV_CSR_HSTATEEN3=1551ULL, RV_CSR_HTIMEDELTAH=1557ULL, RV_CSR_HENVCFGH=1562ULL, RV_CSR_HSTATEEN0H=1564ULL, + RV_CSR_HSTATEEN1H=1565ULL, RV_CSR_HSTATEEN2H=1566ULL, RV_CSR_HSTATEEN3H=1567ULL, RV_CSR_HTVAL=1603ULL, + RV_CSR_HIP=1604ULL, RV_CSR_HVIP=1605ULL, RV_CSR_HTINST=1610ULL, RV_CSR_HGATP=1664ULL, + RV_CSR_HCONTEXT=1704ULL, RV_CSR_MHPMEVENT3H=1827ULL, RV_CSR_MHPMEVENT4H=1828ULL, RV_CSR_MHPMEVENT5H=1829ULL, + RV_CSR_MHPMEVENT6H=1830ULL, RV_CSR_MHPMEVENT7H=1831ULL, RV_CSR_MHPMEVENT8H=1832ULL, RV_CSR_MHPMEVENT9H=1833ULL, + RV_CSR_MHPMEVENT10H=1834ULL, RV_CSR_MHPMEVENT11H=1835ULL, RV_CSR_MHPMEVENT12H=1836ULL, RV_CSR_MHPMEVENT13H=1837ULL, + RV_CSR_MHPMEVENT14H=1838ULL, RV_CSR_MHPMEVENT15H=1839ULL, RV_CSR_MHPMEVENT16H=1840ULL, RV_CSR_MHPMEVENT17H=1841ULL, + RV_CSR_MHPMEVENT18H=1842ULL, RV_CSR_MHPMEVENT19H=1843ULL, RV_CSR_MHPMEVENT20H=1844ULL, RV_CSR_MHPMEVENT21H=1845ULL, + RV_CSR_MHPMEVENT22H=1846ULL, RV_CSR_MHPMEVENT23H=1847ULL, RV_CSR_MHPMEVENT24H=1848ULL, RV_CSR_MHPMEVENT25H=1849ULL, + RV_CSR_MHPMEVENT26H=1850ULL, RV_CSR_MHPMEVENT27H=1851ULL, RV_CSR_MHPMEVENT28H=1852ULL, RV_CSR_MHPMEVENT29H=1853ULL, + RV_CSR_MHPMEVENT30H=1854ULL, RV_CSR_MHPMEVENT31H=1855ULL, RV_CSR_MSECCFG=1863ULL, RV_CSR_MSECCFGH=1879ULL, + RV_CSR_TSELECT=1952ULL, RV_CSR_TDATA1=1953ULL, RV_CSR_TDATA2=1954ULL, RV_CSR_TDATA3=1955ULL, + RV_CSR_TINFO=1956ULL, RV_CSR_TCONTROL=1957ULL, RV_CSR_MCONTEXT=1960ULL, RV_CSR_MSCONTEXT=1962ULL, + RV_CSR_DCSR=1968ULL, RV_CSR_DPC=1969ULL, RV_CSR_DSCRATCH0=1970ULL, RV_CSR_DSCRATCH1=1971ULL, + RV_CSR_MCYCLE=2816ULL, RV_CSR_MINSTRET=2818ULL, RV_CSR_MHPMCOUNTER3=2819ULL, RV_CSR_MHPMCOUNTER4=2820ULL, + RV_CSR_MHPMCOUNTER5=2821ULL, RV_CSR_MHPMCOUNTER6=2822ULL, RV_CSR_MHPMCOUNTER7=2823ULL, RV_CSR_MHPMCOUNTER8=2824ULL, + RV_CSR_MHPMCOUNTER9=2825ULL, RV_CSR_MHPMCOUNTER10=2826ULL, RV_CSR_MHPMCOUNTER11=2827ULL, RV_CSR_MHPMCOUNTER12=2828ULL, + RV_CSR_MHPMCOUNTER13=2829ULL, RV_CSR_MHPMCOUNTER14=2830ULL, RV_CSR_MHPMCOUNTER15=2831ULL, RV_CSR_MHPMCOUNTER16=2832ULL, + RV_CSR_MHPMCOUNTER17=2833ULL, RV_CSR_MHPMCOUNTER18=2834ULL, RV_CSR_MHPMCOUNTER19=2835ULL, RV_CSR_MHPMCOUNTER20=2836ULL, + RV_CSR_MHPMCOUNTER21=2837ULL, RV_CSR_MHPMCOUNTER22=2838ULL, RV_CSR_MHPMCOUNTER23=2839ULL, RV_CSR_MHPMCOUNTER24=2840ULL, + RV_CSR_MHPMCOUNTER25=2841ULL, RV_CSR_MHPMCOUNTER26=2842ULL, RV_CSR_MHPMCOUNTER27=2843ULL, RV_CSR_MHPMCOUNTER28=2844ULL, + RV_CSR_MHPMCOUNTER29=2845ULL, RV_CSR_MHPMCOUNTER30=2846ULL, RV_CSR_MHPMCOUNTER31=2847ULL, RV_CSR_MCYCLEH=2944ULL, + RV_CSR_MINSTRETH=2946ULL, RV_CSR_MHPMCOUNTER3H=2947ULL, RV_CSR_MHPMCOUNTER4H=2948ULL, RV_CSR_MHPMCOUNTER5H=2949ULL, + RV_CSR_MHPMCOUNTER6H=2950ULL, RV_CSR_MHPMCOUNTER7H=2951ULL, RV_CSR_MHPMCOUNTER8H=2952ULL, RV_CSR_MHPMCOUNTER9H=2953ULL, + RV_CSR_MHPMCOUNTER10H=2954ULL, RV_CSR_MHPMCOUNTER11H=2955ULL, RV_CSR_MHPMCOUNTER12H=2956ULL, RV_CSR_MHPMCOUNTER13H=2957ULL, + RV_CSR_MHPMCOUNTER14H=2958ULL, RV_CSR_MHPMCOUNTER15H=2959ULL, RV_CSR_MHPMCOUNTER16H=2960ULL, RV_CSR_MHPMCOUNTER17H=2961ULL, + RV_CSR_MHPMCOUNTER18H=2962ULL, RV_CSR_MHPMCOUNTER19H=2963ULL, RV_CSR_MHPMCOUNTER20H=2964ULL, RV_CSR_MHPMCOUNTER21H=2965ULL, + RV_CSR_MHPMCOUNTER22H=2966ULL, RV_CSR_MHPMCOUNTER23H=2967ULL, RV_CSR_MHPMCOUNTER24H=2968ULL, RV_CSR_MHPMCOUNTER25H=2969ULL, + RV_CSR_MHPMCOUNTER26H=2970ULL, RV_CSR_MHPMCOUNTER27H=2971ULL, RV_CSR_MHPMCOUNTER28H=2972ULL, RV_CSR_MHPMCOUNTER29H=2973ULL, + RV_CSR_MHPMCOUNTER30H=2974ULL, RV_CSR_MHPMCOUNTER31H=2975ULL, RV_CSR_CYCLE=3072ULL, RV_CSR_TIME=3073ULL, + RV_CSR_INSTRET=3074ULL, RV_CSR_HPMCOUNTER3=3075ULL, RV_CSR_HPMCOUNTER4=3076ULL, RV_CSR_HPMCOUNTER5=3077ULL, + RV_CSR_HPMCOUNTER6=3078ULL, RV_CSR_HPMCOUNTER7=3079ULL, RV_CSR_HPMCOUNTER8=3080ULL, RV_CSR_HPMCOUNTER9=3081ULL, + RV_CSR_HPMCOUNTER10=3082ULL, RV_CSR_HPMCOUNTER11=3083ULL, RV_CSR_HPMCOUNTER12=3084ULL, RV_CSR_HPMCOUNTER13=3085ULL, + RV_CSR_HPMCOUNTER14=3086ULL, RV_CSR_HPMCOUNTER15=3087ULL, RV_CSR_HPMCOUNTER16=3088ULL, RV_CSR_HPMCOUNTER17=3089ULL, + RV_CSR_HPMCOUNTER18=3090ULL, RV_CSR_HPMCOUNTER19=3091ULL, RV_CSR_HPMCOUNTER20=3092ULL, RV_CSR_HPMCOUNTER21=3093ULL, + RV_CSR_HPMCOUNTER22=3094ULL, RV_CSR_HPMCOUNTER23=3095ULL, RV_CSR_HPMCOUNTER24=3096ULL, RV_CSR_HPMCOUNTER25=3097ULL, + RV_CSR_HPMCOUNTER26=3098ULL, RV_CSR_HPMCOUNTER27=3099ULL, RV_CSR_HPMCOUNTER28=3100ULL, RV_CSR_HPMCOUNTER29=3101ULL, + RV_CSR_HPMCOUNTER30=3102ULL, RV_CSR_HPMCOUNTER31=3103ULL, RV_CSR_VL=3104ULL, RV_CSR_VTYPE=3105ULL, + RV_CSR_VLENB=3106ULL, RV_CSR_CYCLEH=3200ULL, RV_CSR_TIMEH=3201ULL, RV_CSR_INSTRETH=3202ULL, + RV_CSR_HPMCOUNTER3H=3203ULL, RV_CSR_HPMCOUNTER4H=3204ULL, RV_CSR_HPMCOUNTER5H=3205ULL, RV_CSR_HPMCOUNTER6H=3206ULL, + RV_CSR_HPMCOUNTER7H=3207ULL, RV_CSR_HPMCOUNTER8H=3208ULL, RV_CSR_HPMCOUNTER9H=3209ULL, RV_CSR_HPMCOUNTER10H=3210ULL, + RV_CSR_HPMCOUNTER11H=3211ULL, RV_CSR_HPMCOUNTER12H=3212ULL, RV_CSR_HPMCOUNTER13H=3213ULL, RV_CSR_HPMCOUNTER14H=3214ULL, + RV_CSR_HPMCOUNTER15H=3215ULL, RV_CSR_HPMCOUNTER16H=3216ULL, RV_CSR_HPMCOUNTER17H=3217ULL, RV_CSR_HPMCOUNTER18H=3218ULL, + RV_CSR_HPMCOUNTER19H=3219ULL, RV_CSR_HPMCOUNTER20H=3220ULL, RV_CSR_HPMCOUNTER21H=3221ULL, RV_CSR_HPMCOUNTER22H=3222ULL, + RV_CSR_HPMCOUNTER23H=3223ULL, RV_CSR_HPMCOUNTER24H=3224ULL, RV_CSR_HPMCOUNTER25H=3225ULL, RV_CSR_HPMCOUNTER26H=3226ULL, + RV_CSR_HPMCOUNTER27H=3227ULL, RV_CSR_HPMCOUNTER28H=3228ULL, RV_CSR_HPMCOUNTER29H=3229ULL, RV_CSR_HPMCOUNTER30H=3230ULL, + RV_CSR_HPMCOUNTER31H=3231ULL, RV_CSR_SCOUNTOVF=3488ULL, RV_CSR_HGEIP=3602ULL, RV_CSR_MVENDORID=3857ULL, + RV_CSR_MARCHID=3858ULL, RV_CSR_MIMPID=3859ULL, RV_CSR_MHARTID=3860ULL, RV_CSR_MCONFIGPTR=3861ULL, + RV_CAUSE_MISALIGNED_FETCH=0ULL, RV_CAUSE_FETCH_ACCESS=1ULL, RV_CAUSE_ILLEGAL_INSTRUCTION=2ULL, RV_CAUSE_BREAKPOINT=3ULL, + RV_CAUSE_MISALIGNED_LOAD=4ULL, RV_CAUSE_LOAD_ACCESS=5ULL, RV_CAUSE_MISALIGNED_STORE=6ULL, RV_CAUSE_STORE_ACCESS=7ULL, + RV_CAUSE_USER_ECALL=8ULL, RV_CAUSE_SUPERVISOR_ECALL=9ULL, RV_CAUSE_VIRTUAL_SUPERVISOR_ECALL=10ULL, RV_CAUSE_MACHINE_ECALL=11ULL, + RV_CAUSE_FETCH_PAGE_FAULT=12ULL, RV_CAUSE_LOAD_PAGE_FAULT=13ULL, RV_CAUSE_STORE_PAGE_FAULT=15ULL, RV_CAUSE_FETCH_GUEST_PAGE_FAULT=20ULL, + RV_CAUSE_LOAD_GUEST_PAGE_FAULT=21ULL, RV_CAUSE_VIRTUAL_INSTRUCTION=22ULL, RV_CAUSE_STORE_GUEST_PAGE_FAULT=23ULL, RV_MSTATUS_UIE=1ULL, + RV_MSTATUS_SIE=2ULL, RV_MSTATUS_HIE=4ULL, RV_MSTATUS_MIE=8ULL, RV_MSTATUS_UPIE=16ULL, + RV_MSTATUS_SPIE=32ULL, RV_MSTATUS_UBE=64ULL, RV_MSTATUS_MPIE=128ULL, RV_MSTATUS_SPP=256ULL, + RV_MSTATUS_VS=1536ULL, RV_MSTATUS_MPP=6144ULL, RV_MSTATUS_FS=24576ULL, RV_MSTATUS_XS=98304ULL, + RV_MSTATUS_MPRV=131072ULL, RV_MSTATUS_SUM=262144ULL, RV_MSTATUS_MXR=524288ULL, RV_MSTATUS_TVM=1048576ULL, + RV_MSTATUS_TW=2097152ULL, RV_MSTATUS_TSR=4194304ULL, RV_MSTATUS32_SD=2147483648ULL, RV_MSTATUS_UXL=12884901888ULL, + RV_MSTATUS_SXL=51539607552ULL, RV_MSTATUS_SBE=68719476736ULL, RV_MSTATUS_MBE=137438953472ULL, RV_MSTATUS_GVA=274877906944ULL, + RV_MSTATUS_MPV=549755813888ULL, RV_MSTATUS64_SD=9223372036854775808ULL, RV_PRV_U=0ULL, RV_PRV_S=1ULL, + RV_PRV_H=2ULL, RV_PRV_M=3ULL, RV_IRQ_U_SOFT=0ULL, RV_IRQ_S_SOFT=1ULL, + 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=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=2ULL, RFS=32ULL, fence=0ULL, + fencei=1ULL, fencevma=2ULL, CSR_SIZE=4096ULL, MUL_LEN=128ULL, + MISA_VAL=9223372036854780165ULL, MARCHID_VAL=0ULL, CLIC_NUM_IRQ=0ULL + }; + + + constexpr static unsigned FP_REGS_SIZE = 0; + constexpr static unsigned V_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 = uint64_t; + + using addr_t = uint64_t; + + using code_word_t = uint64_t; //TODO: check removal + + using virt_addr_t = iss::virt_addr_t; + + using phys_addr_t = iss::phys_addr_t; + + static constexpr std::array reg_bit_widths{{ + sizeof(rv64imac::RV64IMAC_regs::X0) * 8, + sizeof(rv64imac::RV64IMAC_regs::X1) * 8, + sizeof(rv64imac::RV64IMAC_regs::X2) * 8, + sizeof(rv64imac::RV64IMAC_regs::X3) * 8, + sizeof(rv64imac::RV64IMAC_regs::X4) * 8, + sizeof(rv64imac::RV64IMAC_regs::X5) * 8, + sizeof(rv64imac::RV64IMAC_regs::X6) * 8, + sizeof(rv64imac::RV64IMAC_regs::X7) * 8, + sizeof(rv64imac::RV64IMAC_regs::X8) * 8, + sizeof(rv64imac::RV64IMAC_regs::X9) * 8, + sizeof(rv64imac::RV64IMAC_regs::X10) * 8, + sizeof(rv64imac::RV64IMAC_regs::X11) * 8, + sizeof(rv64imac::RV64IMAC_regs::X12) * 8, + sizeof(rv64imac::RV64IMAC_regs::X13) * 8, + sizeof(rv64imac::RV64IMAC_regs::X14) * 8, + sizeof(rv64imac::RV64IMAC_regs::X15) * 8, + sizeof(rv64imac::RV64IMAC_regs::X16) * 8, + sizeof(rv64imac::RV64IMAC_regs::X17) * 8, + sizeof(rv64imac::RV64IMAC_regs::X18) * 8, + sizeof(rv64imac::RV64IMAC_regs::X19) * 8, + sizeof(rv64imac::RV64IMAC_regs::X20) * 8, + sizeof(rv64imac::RV64IMAC_regs::X21) * 8, + sizeof(rv64imac::RV64IMAC_regs::X22) * 8, + sizeof(rv64imac::RV64IMAC_regs::X23) * 8, + sizeof(rv64imac::RV64IMAC_regs::X24) * 8, + sizeof(rv64imac::RV64IMAC_regs::X25) * 8, + sizeof(rv64imac::RV64IMAC_regs::X26) * 8, + sizeof(rv64imac::RV64IMAC_regs::X27) * 8, + sizeof(rv64imac::RV64IMAC_regs::X28) * 8, + sizeof(rv64imac::RV64IMAC_regs::X29) * 8, + sizeof(rv64imac::RV64IMAC_regs::X30) * 8, + sizeof(rv64imac::RV64IMAC_regs::X31) * 8, + sizeof(rv64imac::RV64IMAC_regs::PC) * 8, + sizeof(rv64imac::RV64IMAC_regs::NEXT_PC) * 8, + sizeof(rv64imac::RV64IMAC_regs::PRIV) * 8, + sizeof(rv64imac::RV64IMAC_regs::DPC) * 8, + sizeof(rv64imac::RV64IMAC_regs::trap_state) * 8, + sizeof(rv64imac::RV64IMAC_regs::pending_trap) * 8, + sizeof(rv64imac::RV64IMAC_regs::icount) * 8, + sizeof(rv64imac::RV64IMAC_regs::cycle) * 8, + sizeof(rv64imac::RV64IMAC_regs::instret) * 8, + sizeof(rv64imac::RV64IMAC_regs::instruction) * 8, + sizeof(rv64imac::RV64IMAC_regs::last_branch) * 8, + }}; + + static constexpr std::array reg_byte_offsets{{ + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X0), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X1), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X2), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X3), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X4), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X5), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X6), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X7), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X8), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X9), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X10), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X11), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X12), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X13), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X14), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X15), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X16), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X17), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X18), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X19), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X20), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X21), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X22), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X23), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X24), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X25), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X26), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X27), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X28), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X29), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X30), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::X31), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::PC), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::NEXT_PC), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::PRIV), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::DPC), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::trap_state), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::pending_trap), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::icount), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::cycle), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::instret), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::instruction), + offsetof(rv64imac::RV64IMAC_regs, rv64imac::RV64IMAC_regs::last_branch), + }}; + + 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 = 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, + 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, + LWU = 42, + LD = 43, + SD = 44, + ADDIW = 45, + SLLIW = 46, + SRLIW = 47, + SRAIW = 48, + ADDW = 49, + SUBW = 50, + SLLW = 51, + SRLW = 52, + SRAW = 53, + CSRRW = 54, + CSRRS = 55, + CSRRC = 56, + CSRRWI = 57, + CSRRSI = 58, + CSRRCI = 59, + FENCE_I = 60, + MUL = 61, + MULH = 62, + MULHSU = 63, + MULHU = 64, + DIV = 65, + DIVU = 66, + REM = 67, + REMU = 68, + MULW = 69, + DIVW = 70, + DIVUW = 71, + REMW = 72, + REMUW = 73, + LRW = 74, + SCW = 75, + AMOSWAPW = 76, + AMOADDW = 77, + AMOXORW = 78, + AMOANDW = 79, + AMOORW = 80, + AMOMINW = 81, + AMOMAXW = 82, + AMOMINUW = 83, + AMOMAXUW = 84, + LRD = 85, + SCD = 86, + AMOSWAPD = 87, + AMOADDD = 88, + AMOXORD = 89, + AMOANDD = 90, + AMOORD = 91, + AMOMIND = 92, + AMOMAXD = 93, + AMOMINUD = 94, + AMOMAXUD = 95, + C__ADDI4SPN = 96, + C__LW = 97, + C__LD = 98, + C__SW = 99, + C__SD = 100, + C__ADDI = 101, + C__NOP = 102, + C__ADDIW = 103, + C__LI = 104, + C__LUI = 105, + C__ADDI16SP = 106, + __reserved_clui = 107, + C__SRLI = 108, + C__SRAI = 109, + C__ANDI = 110, + C__SUB = 111, + C__XOR = 112, + C__OR = 113, + C__AND = 114, + C__SUBW = 115, + C__ADDW = 116, + C__J = 117, + C__BEQZ = 118, + C__BNEZ = 119, + C__SLLI = 120, + C__LWSP = 121, + C__LDSP = 122, + C__MV = 123, + C__JR = 124, + __reserved_cmv = 125, + C__ADD = 126, + C__JALR = 127, + C__EBREAK = 128, + C__SWSP = 129, + C__SDSP = 130, + DII = 131, + MAX_OPCODE + }; +}; +} +} +#endif /* _RV64IMAC_H_ */ +// clang-format on diff --git a/src/iss/arch/tgc5c.h b/src/iss/arch/tgc5c.h index 3ce02ec..9ab9b2b 100644 --- a/src/iss/arch/tgc5c.h +++ b/src/iss/arch/tgc5c.h @@ -64,6 +64,8 @@ struct tgc5c: public arch_if { virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + virtual void enable_disass(bool) = 0; + struct TGC5C_regs { uint32_t X0 = 0; uint32_t X1 = 0; @@ -127,8 +129,6 @@ struct tgc5c: public arch_if { }; -struct tgc5c; - template <> struct traits { constexpr static char const* const core_type = "TGC5C"; @@ -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..16fa006 100644 --- a/src/iss/debugger/riscv_target_adapter.h +++ b/src/iss/debugger/riscv_target_adapter.h @@ -34,6 +34,7 @@ #define _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_ #include "iss/arch_if.h" +#include "iss/debugger/target_adapter_if.h" #include #include #include @@ -52,9 +53,6 @@ char const* const get_csr_name(unsigned); constexpr auto vec_offset = 128U; constexpr auto csr_offset = 256U; -using namespace iss::arch; -using namespace iss::debugger; - template class riscv_target_adapter : public target_adapter_base { public: riscv_target_adapter(server_if* srv, iss::arch_if* core) @@ -80,6 +78,8 @@ template class riscv_target_adapter : public target_adapter_base avail buf is 1 */ status read_registers(std::vector& data, std::vector& avail) override; + status trigger_debugger_stop_event() override; + /* Write all registers. buf is 4-byte aligned and it is in target byte order */ status write_registers(const std::vector& data) override; @@ -115,7 +115,7 @@ template class riscv_target_adapter : public target_adapter_base status crc_query(uint64_t addr, size_t len, uint32_t& val) override; - status raw_query(std::string in_buf, std::string& out_buf) override; + status raw_query(const std::string& in_buf, std::string& out_buf) override; status threadinfo_query(int first, std::string& out_buf) override; @@ -133,7 +133,7 @@ template class riscv_target_adapter : public target_adapter_base protected: static inline constexpr addr_t map_addr(const addr_t& i) { return i; } - std::string csr_xml; + std::string register_xml; iss::arch_if* core; rp_thread_ref thread_idx; }; @@ -183,6 +183,10 @@ template status riscv_target_adapter::current_thread_query return Ok; } +template status riscv_target_adapter::trigger_debugger_stop_event() { + core->cancel_wait(); + return Ok; +} template status riscv_target_adapter::read_registers(std::vector& data, std::vector& avail) { CPPLOG(TRACE) << "reading target registers"; data.clear(); @@ -192,7 +196,7 @@ template status riscv_target_adapter::read_registers(std:: for(size_t i = 0; i < 33; ++i) { if(i < arch::traits::RFS || i == arch::traits::PC) { auto reg_no = i < 32 ? start_reg + i : arch::traits::PC; - unsigned offset = traits::reg_byte_offsets[reg_no]; + unsigned offset = iss::arch::traits::reg_byte_offsets[reg_no]; for(size_t j = 0; j < arch::traits::XLEN / 8; ++j) { data.push_back(*(reg_base + offset + j)); avail.push_back(0xff); @@ -214,11 +218,13 @@ template status riscv_target_adapter::write_registers(cons auto iter_end = data.data() + data.size(); for(size_t i = 0; i < 33 && iter < iter_end; ++i) { auto reg_width = arch::traits::XLEN / 8; + if(iter_end - iter < static_cast(reg_width)) + return Err; if(i < arch::traits::RFS) { - auto offset = traits::reg_byte_offsets[start_reg + i]; + auto offset = iss::arch::traits::reg_byte_offsets[start_reg + i]; std::copy(iter, iter + reg_width, reg_base + offset); } else if(i == 32) { - auto offset = traits::reg_byte_offsets[arch::traits::PC]; + auto offset = iss::arch::traits::reg_byte_offsets[arch::traits::PC]; std::copy(iter, iter + reg_width, reg_base + offset); } iter += reg_width; @@ -228,24 +234,32 @@ template status riscv_target_adapter::write_registers(cons template status riscv_target_adapter::read_single_register(unsigned int reg_no, std::vector& data, std::vector& avail) { + data.clear(); + avail.clear(); if(reg_no < vec_offset) { - // auto reg_size = arch::traits::reg_bit_width(static_cast::reg_e>(reg_no))/8; + if(reg_no >= iss::arch::traits::reg_bit_widths.size() || reg_no >= iss::arch::traits::reg_byte_offsets.size()) + return Err; auto* reg_base = core->get_regs_base_ptr(); auto reg_width = arch::traits::reg_bit_widths[reg_no] / 8; + if(reg_width == 0) + return Err; data.resize(reg_width); avail.resize(reg_width); - auto offset = traits::reg_byte_offsets[reg_no]; + auto offset = iss::arch::traits::reg_byte_offsets[reg_no]; std::copy(reg_base + offset, reg_base + offset + reg_width, data.begin()); std::fill(avail.begin(), avail.end(), 0xff); } else if(reg_no < csr_offset) { // TODO: implement vector register reading + return Err; } else { - typed_addr_t a(iss::access_type::DEBUG_READ, traits::CSR, reg_no - csr_offset); - data.resize(sizeof(typename traits::reg_t)); - avail.resize(sizeof(typename traits::reg_t)); - std::fill(avail.begin(), avail.end(), 0xff); - core->read(a, data.size(), data.data()); + typed_addr_t a(iss::access_type::DEBUG_READ, iss::arch::traits::CSR, reg_no - csr_offset); + data.resize(sizeof(typename iss::arch::traits::reg_t)); + avail.resize(sizeof(typename iss::arch::traits::reg_t)); + auto res = core->read(a, data.size(), data.data()); + if(res != Ok) { + std::fill(avail.begin(), avail.end(), 0); + return res; + } std::fill(avail.begin(), avail.end(), 0xff); } return data.size() > 0 ? Ok : Err; @@ -253,29 +267,40 @@ status riscv_target_adapter::read_single_register(unsigned int reg_no, std template status riscv_target_adapter::write_single_register(unsigned int reg_no, const std::vector& data) { if(reg_no < vec_offset) { + if(reg_no >= iss::arch::traits::reg_bit_widths.size() || reg_no >= iss::arch::traits::reg_byte_offsets.size()) + return Err; auto* reg_base = core->get_regs_base_ptr(); auto reg_width = arch::traits::reg_bit_widths[static_cast::reg_e>(reg_no)] / 8; - auto offset = traits::reg_byte_offsets[reg_no]; + if(data.size() < reg_width) + return Err; + auto offset = iss::arch::traits::reg_byte_offsets[reg_no]; std::copy(data.begin(), data.begin() + reg_width, reg_base + offset); } else if(reg_no < csr_offset) { // TODO: implement vector register writing + return Err; } else { - typed_addr_t a(iss::access_type::DEBUG_WRITE, traits::CSR, reg_no - csr_offset); - core->write(a, data.size(), data.data()); + typed_addr_t a(iss::access_type::DEBUG_WRITE, iss::arch::traits::CSR, reg_no - csr_offset); + auto res = core->write(a, data.size(), data.data()); + if(res != Ok) + return res; } return Ok; } 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}); + if(!srv) + return Err; + 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); + return srv->execute_synchronized(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}); + if(!srv) + return Err; + 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); + return srv->execute_synchronized(f); } template @@ -292,7 +317,9 @@ template status riscv_target_adapter::offsets_query(uint64 template status riscv_target_adapter::crc_query(uint64_t addr, size_t len, uint32_t& val) { return NotSupported; } -template status riscv_target_adapter::raw_query(std::string in_buf, std::string& out_buf) { return NotSupported; } +template status riscv_target_adapter::raw_query(const std::string& in_buf, std::string& out_buf) { + return NotSupported; +} template status riscv_target_adapter::threadinfo_query(int first, std::string& out_buf) { if(first) { @@ -317,40 +344,51 @@ template status riscv_target_adapter::packetsize_query(std } template status riscv_target_adapter::add_break(break_type type, uint64_t addr, unsigned int length) { + auto f = [](riscv_target_adapter* self, util::range_lut& lut, uint64_t addr, unsigned int 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}); + lut.addEntry(++self->bp_count, saddr.val, eaddr.val - saddr.val); + CPPLOG(TRACE) << "Adding breakpoint with handle " << self->bp_count << " for addr 0x" << std::hex << saddr.val << std::dec; + CPPLOG(TRACE) << "Now having " << self->bp_lut.size() + self->wr_lut.size() + self->rd_lut.size() << " breakpoints"; + return Ok; + }; switch(type) { default: 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}); - 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; - CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; - return Ok; - } + case HW_EXEC: + return f(this, this->bp_lut, addr, length); + case RD_WATCH: + return f(this, this->rd_lut, addr, length); + case WR_WATCH: + return f(this, this->wr_lut, addr, length); } } template status riscv_target_adapter::remove_break(break_type type, uint64_t addr, unsigned int length) { - switch(type) { - default: - return Err; - case SW_EXEC: - case HW_EXEC: { - auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); - unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val); + auto f = [](riscv_target_adapter* self, util::range_lut& lut, uint64_t addr, unsigned int length) { + auto saddr = map_addr({iss::address_type::PHYSICAL, iss::access_type::FETCH, 0, addr}); + unsigned handle = lut.getEntry(saddr.val); if(handle) { CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec; // TODO: check length of addr range - target_adapter_base::bp_lut.removeEntry(handle); - CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; + lut.removeEntry(handle); + CPPLOG(TRACE) << "Now having " << self->bp_lut.size() + self->wr_lut.size() + self->rd_lut.size() << " breakpoints"; return Ok; } - CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; + CPPLOG(TRACE) << "Now having " << self->bp_lut.size() + self->wr_lut.size() + self->rd_lut.size() << " breakpoints"; return Err; - } + }; + switch(type) { + default: + return Err; + case SW_EXEC: + case HW_EXEC: + return f(this, this->bp_lut, addr, length); + case RD_WATCH: + return f(this, this->rd_lut, addr, length); + case WR_WATCH: + return f(this, this->wr_lut, addr, length); } } @@ -359,9 +397,9 @@ status riscv_target_adapter::resume_from_addr(bool step, int sig, uint64_t std::function stop_callback) { auto* reg_base = core->get_regs_base_ptr(); auto reg_width = arch::traits::reg_bit_widths[arch::traits::PC] / 8; - auto offset = traits::reg_byte_offsets[arch::traits::PC]; + auto offset = iss::arch::traits::reg_byte_offsets[arch::traits::PC]; const uint8_t* iter = reinterpret_cast(&addr); - std::copy(iter, iter + reg_width, reg_base); + std::copy(iter, iter + reg_width, reg_base + offset); return resume_from_current(step, sig, thread, stop_callback); } @@ -382,7 +420,7 @@ template status riscv_target_adapter::target_xml_query(std {"uint8", "bytes", 8, 'b'}, }}; - if(!csr_xml.size()) { + if(!register_xml.size()) { std::ostringstream oss; oss << "\n"; if(iss::arch::traits::XLEN == 32) @@ -409,8 +447,8 @@ template status riscv_target_adapter::target_xml_query(std oss << " \n"; } std::vector data; - data.resize(sizeof(typename traits::reg_t)); - typed_addr_t vlen_addr(iss::access_type::DEBUG_READ, traits::CSR, 0xC22); + data.resize(sizeof(typename iss::arch::traits::reg_t)); + typed_addr_t vlen_addr(iss::access_type::DEBUG_READ, iss::arch::traits::CSR, 0xC22); auto res = core->read(vlen_addr, data.size(), data.data()); if(res == iss::Ok) { auto bitsize = data[0] * 8L; @@ -430,23 +468,25 @@ template status riscv_target_adapter::target_xml_query(std } oss << " \n"; } - oss << " \n"; - std::vector avail; - avail.resize(sizeof(typename traits::reg_t)); - for(auto i = 0U; i < 4096; ++i) { - typed_addr_t a(iss::access_type::DEBUG_READ, traits::CSR, i); - std::fill(avail.begin(), avail.end(), 0xff); - auto res = core->read(a, data.size(), data.data()); - if(res == iss::Ok) { - oss << " ::XLEN - << "\" type=\"int\" regnum=\"" << (i + csr_offset) << "\"/>\n"; + if(this->srv->report_all_regs()) { + oss << " \n"; + std::vector avail; + avail.resize(sizeof(typename iss::arch::traits::reg_t)); + for(auto i = 0U; i < 4096; ++i) { + typed_addr_t a(iss::access_type::DEBUG_READ, iss::arch::traits::CSR, i); + std::fill(avail.begin(), avail.end(), 0xff); + auto res = core->read(a, data.size(), data.data()); + if(res == iss::Ok) { + oss << " ::XLEN + << "\" type=\"int\" regnum=\"" << (i + csr_offset) << "\"/>\n"; + } } + oss << " \n"; } - oss << " \n"; oss << "\n"; - csr_xml = oss.str(); + register_xml = oss.str(); } - out_buf = csr_xml; + out_buf = register_xml; return Ok; } } // namespace debugger diff --git a/src/iss/mem/clic.h b/src/iss/mem/clic.h index 1a4d3fc..ee5c057 100644 --- a/src/iss/mem/clic.h +++ b/src/iss/mem/clic.h @@ -32,9 +32,12 @@ * eyck@minres.com - initial implementation ******************************************************************************/ -#include "memory_if.h" +#ifndef ISS_MEM_CLIC_H +#define ISS_MEM_CLIC_H + #include "iss/arch/riscv_hart_common.h" #include "iss/vm_types.h" +#include "memory_if.h" #include namespace iss { @@ -46,7 +49,7 @@ struct clic_config { unsigned clic_num_trigger{0}; bool nmode{false}; }; - +namespace { inline void read_reg_with_offset(uint32_t reg, uint8_t offs, uint8_t* const data, unsigned length) { auto reg_ptr = reinterpret_cast(®); switch(offs) { @@ -88,41 +91,43 @@ inline void write_reg_with_offset(uint32_t& reg, uint8_t offs, const uint8_t* co break; } } +} // namespace template struct clic : public memory_elem { using this_class = clic; using reg_t = WORD_TYPE; constexpr static unsigned WORD_LEN = sizeof(WORD_TYPE) * 8; - clic(arch::priv_if hart_if, clic_config cfg) + clic(arch::priv_if hart_if, clic_config const& cfg) : hart_if(hart_if) , cfg(cfg) { clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0}); clic_cfg_reg = 0x30; clic_mact_lvl = clic_mprev_lvl = (1 << (cfg.clic_int_ctl_bits)) - 1; clic_uact_lvl = clic_uprev_lvl = (1 << (cfg.clic_int_ctl_bits)) - 1; - hart_if.csr_rd_cb[arch::mtvt] = MK_CSR_RD_CB(read_plain); + hart_if.csr_rd_cb[arch::mcause] = MK_CSR_RD_CB(read_cause); + hart_if.csr_wr_cb[arch::mcause] = MK_CSR_WR_CB(write_cause); + hart_if.csr_rd_cb[arch::mtvec] = MK_CSR_RD_CB(read_xtvec); + hart_if.csr_wr_cb[arch::mtvec] = MK_CSR_WR_CB(write_xtvec); + hart_if.csr_rd_cb[arch::mtvt] = MK_CSR_RD_CB(read_xtvt); hart_if.csr_wr_cb[arch::mtvt] = MK_CSR_WR_CB(write_xtvt); - // hart_if.csr_rd_cb[mxnti] = MK_CSR_RD_CB(read_plain(a,r);}; - // hart_if.csr_wr_cb[mxnti] = MK_CSR_WR_CB(write_plain(a,r);}; hart_if.csr_rd_cb[arch::mintstatus] = MK_CSR_RD_CB(read_intstatus); hart_if.csr_wr_cb[arch::mintstatus] = MK_CSR_WR_CB(write_null); - // hart_if.csr_rd_cb[mscratchcsw] = MK_CSR_RD_CB(read_plain(a,r);}; - // hart_if.csr_wr_cb[mscratchcsw] = MK_CSR_WR_CB(write_plain(a,r);}; - // hart_if.csr_rd_cb[mscratchcswl] = MK_CSR_RD_CB(read_plain(a,r);}; - // hart_if.csr_wr_cb[mscratchcswl] = MK_CSR_WR_CB(write_plain(a,r);}; - hart_if.csr_rd_cb[arch::mintthresh] = MK_CSR_RD_CB(read_plain); + hart_if.csr_rd_cb[arch::mintthresh] = MK_CSR_RD_CB(read_intthresh); hart_if.csr_wr_cb[arch::mintthresh] = MK_CSR_WR_CB(write_intthresh); if(cfg.nmode) { - hart_if.csr_rd_cb[arch::utvt] = MK_CSR_RD_CB(read_plain); + hart_if.csr_rd_cb[arch::ucause] = MK_CSR_RD_CB(read_cause); + hart_if.csr_wr_cb[arch::ucause] = MK_CSR_WR_CB(write_cause); + hart_if.csr_rd_cb[arch::utvec] = MK_CSR_RD_CB(read_xtvec); + hart_if.csr_rd_cb[arch::utvt] = MK_CSR_RD_CB(read_xtvt); hart_if.csr_wr_cb[arch::utvt] = MK_CSR_WR_CB(write_xtvt); hart_if.csr_rd_cb[arch::uintstatus] = MK_CSR_RD_CB(read_intstatus); hart_if.csr_wr_cb[arch::uintstatus] = MK_CSR_WR_CB(write_null); - hart_if.csr_rd_cb[arch::uintthresh] = MK_CSR_RD_CB(read_plain); + hart_if.csr_rd_cb[arch::uintthresh] = MK_CSR_RD_CB(read_intthresh); hart_if.csr_wr_cb[arch::uintthresh] = MK_CSR_WR_CB(write_intthresh); } - hart_if.csr[arch::mintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; - hart_if.csr[arch::uintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; + clic_intthresh[arch::mintthresh >> 8] = (1 << (cfg.clic_int_ctl_bits)) - 1; + clic_intthresh[arch::uintthresh >> 8] = (1 << (cfg.clic_int_ctl_bits)) - 1; } ~clic() = default; @@ -137,16 +142,20 @@ template struct clic : public memory_elem { std::tuple get_range() override { return {cfg.clic_base, cfg.clic_base + 0x7fff}; } private: - iss::status read_mem(iss::access_type access, uint64_t addr, unsigned length, uint8_t* data) { - if(addr >= cfg.clic_base && (addr + length) < (cfg.clic_base + 0x8000)) - return read_clic(addr, length, data); - return down_stream_mem.rd_mem(access, addr, length, data); + iss::status read_mem(addr_t const& addr, unsigned length, uint8_t* data) { + auto end_addr = addr.val - 1 + length; + if(addr.space == 0 && addr.val <= end_addr && addr.val >= cfg.clic_base && end_addr <= (cfg.clic_base + 0x7fff)) + if(read_clic(addr.val, length, data) == iss::Ok) + return iss::Ok; + 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(addr >= cfg.clic_base && (addr + length) < (cfg.clic_base + 0x8000)) - return write_clic(addr, length, data); - return down_stream_mem.wr_mem(access, addr, length, data); + iss::status write_mem(addr_t const& addr, unsigned length, uint8_t const* data) { + auto end_addr = addr.val - 1 + length; + if(addr.space == 0 && addr.val <= end_addr && addr.val >= cfg.clic_base && end_addr <= (cfg.clic_base + 0x7fff)) + if(write_clic(addr.val, length, data) == iss::Ok) + return iss::Ok; + return down_stream_mem.wr_mem(addr, length, data); } iss::status read_clic(uint64_t addr, unsigned length, uint8_t* data); @@ -155,21 +164,77 @@ template struct clic : public memory_elem { iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } - iss::status read_plain(unsigned addr, reg_t& val) { - val = hart_if.csr[addr]; + iss::status read_xtvt(unsigned addr, reg_t& val) { + val = clic_xtvt[addr >> 8]; return iss::Ok; } iss::status write_xtvt(unsigned addr, reg_t val) { - hart_if.csr[addr] = val & ~0x3fULL; + clic_xtvt[addr >> 8] = val & ~0x3fULL; + return iss::Ok; + } + + iss::status read_intstatus(unsigned addr, reg_t& val) { + auto mode = (addr >> 8) & 0x3; + val = clic_uact_lvl & 0xff; + if(mode == 0x3) + val += (clic_mact_lvl & 0xff) << 24; + return iss::Ok; + } + + iss::status read_intthresh(unsigned addr, reg_t& val) { + val = clic_intthresh[addr >> 8]; + return iss::Ok; + } + + iss::status write_intthresh(unsigned addr, reg_t val) { + clic_intthresh[addr >> 8] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; + return iss::Ok; + } + + iss::status read_xtvec(unsigned addr, reg_t& val) { + val = hart_if.get_csr(addr); return iss::Ok; } - iss::status read_cause(unsigned addr, reg_t& val); - iss::status write_cause(unsigned addr, reg_t val); + iss::status write_xtvec(unsigned addr, reg_t val) { + hart_if.set_csr(addr, val); + if((val & 0x3) != 0x3) { + clic_mprev_lvl = 0xff >> cfg.clic_int_ctl_bits; + clic_uprev_lvl = 0xff >> cfg.clic_int_ctl_bits; + } + return iss::Ok; + } - iss::status read_intstatus(unsigned addr, reg_t& val); - iss::status write_intthresh(unsigned addr, reg_t val); + iss::status read_cause(unsigned addr, reg_t& val) { + val = hart_if.get_csr(addr) & ((1UL << (WORD_LEN - 1)) | (hart_if.max_irq - 1)); + auto xtvec = hart_if.get_csr(arch::mtvec); + if((xtvec & 0x3) == 0x3) { + if(addr == arch::mcause) { // mcause access + val |= hart_if.state.mstatus.MPP << 28 | hart_if.state.mstatus.MPIE << 27 | clic_mprev_lvl << 16; + } else if(addr == arch::ucause) { + val |= hart_if.state.mstatus.UPIE << 27 | clic_uprev_lvl << 16; + } + } + return iss::Ok; + } + + iss::status write_cause(unsigned addr, reg_t val) { + auto mask = ((1UL << (WORD_LEN - 1)) | (hart_if.max_irq - 1)); + hart_if.set_csr(addr, (val & mask) | (hart_if.get_csr(addr) & ~mask)); + auto xtvec = hart_if.get_csr(arch::mtvec); + if((xtvec & 0x3) == 0x3) { + if(addr == arch::mcause) { // mcause access + hart_if.state.mstatus.MPIE = (val >> 27) & 1; + clic_mprev_lvl = ((val >> 16) & 0xff) | 0xff >> cfg.clic_int_ctl_bits; + hart_if.state.mstatus.MPP = (val >> 28) & 0x3; + } else if(addr == arch::ucause) { + hart_if.state.mstatus.UPIE = (val >> 27) & 1; + clic_uprev_lvl = ((val >> 16) & 0xff) | 0xff >> cfg.clic_int_ctl_bits; + } + } + return iss::Ok; + } protected: arch::priv_if hart_if; @@ -189,97 +254,55 @@ template struct clic : public memory_elem { std::vector clic_int_reg; uint8_t clic_mprev_lvl{0}, clic_uprev_lvl{0}; uint8_t clic_mact_lvl{0}, clic_uact_lvl{0}; + std::array clic_intthresh{0}; + std::array clic_xtvt{0}; }; template iss::status clic::read_clic(uint64_t addr, unsigned length, uint8_t* const data) { - if(addr == cfg.clic_base) { // cliccfg - *data = clic_cfg_reg; - for(auto i = 1; i < length; ++i) - *(data + i) = 0; + if(addr >= cfg.clic_base && addr < (cfg.clic_base + 4)) { // cliccfg + std::array reg = {clic_cfg_reg, 0, 0, 0}; + auto offset = addr - cfg.clic_base; + for(auto i = 0; i < length; ++i) + *(data + i) = (i + offset) < reg.size() ? reg[offset + i] : 0; + return iss::Ok; +#if 0 } else if(addr >= (cfg.clic_base + 0x40) && (addr + length) <= (cfg.clic_base + 0x40 + cfg.clic_num_trigger * 4)) { // clicinttrig auto offset = ((addr & 0x7fff) - 0x40) / 4; read_reg_with_offset(clic_inttrig_reg[offset], addr & 0x3, data, length); + return iss::Ok; +#endif } else if(addr >= (cfg.clic_base + 0x1000) && - (addr + length) <= (cfg.clic_base + 0x1000 + cfg.clic_num_irq * 4)) { // clicintip/clicintie/clicintattr/clicintctl + addr < (cfg.clic_base + 0x1000 + cfg.clic_num_irq * 4)) { // clicintip/clicintie/clicintattr/clicintctl auto offset = ((addr & 0x7fff) - 0x1000) / 4; read_reg_with_offset(clic_int_reg[offset].raw, addr & 0x3, data, length); - } else { - for(auto i = 0U; i < length; ++i) - *(data + i) = 0; + return iss::Ok; } - return iss::Ok; + return iss::NotSupported; } template iss::status clic::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) { - if(addr == cfg.clic_base) { // cliccfg - clic_cfg_reg = (clic_cfg_reg & ~0x1e) | (*data & 0x1e); + if(addr >= cfg.clic_base && addr < (cfg.clic_base + 4)) { // cliccfg + auto offset = addr - cfg.clic_base; + for(auto i = 0; i < length; ++i) + if((i + offset) == 0) + clic_cfg_reg = (clic_cfg_reg & ~0x1e) | (*data & 0x1e); + return iss::Ok; +#if 0 } else if(addr >= (cfg.clic_base + 0x40) && (addr + length) <= (cfg.clic_base + 0x40 + cfg.clic_num_trigger * 4)) { // clicinttrig auto offset = ((addr & 0x7fff) - 0x40) / 4; write_reg_with_offset(clic_inttrig_reg[offset], addr & 0x3, data, length); + return iss::Ok; +#endif } else if(addr >= (cfg.clic_base + 0x1000) && - (addr + length) <= (cfg.clic_base + 0x1000 + cfg.clic_num_irq * 4)) { // clicintip/clicintie/clicintattr/clicintctl + addr < (cfg.clic_base + 0x1000 + cfg.clic_num_irq * 4)) { // clicintip/clicintie/clicintattr/clicintctl auto offset = ((addr & 0x7fff) - 0x1000) / 4; write_reg_with_offset(clic_int_reg[offset].raw, addr & 0x3, data, length); clic_int_reg[offset].raw &= 0xf0c70101; // clicIntCtlBits->0xf0, clicintattr->0xc7, clicintie->0x1, clicintip->0x1 + return iss::Ok; } - return iss::Ok; -} - -template iss::status clic::read_cause(unsigned addr, reg_t& val) { - if((hart_if.csr[arch::mtvec] & 0x3) == 3) { - val = hart_if.csr[addr] & (1UL << (sizeof(reg_t) * 8) | (hart_if.mcause_max_irq - 1) | (0xfUL << 16)); - auto mode = (addr >> 8) & 0x3; - switch(mode) { - case 0: - val |= clic_uprev_lvl << 16; - val |= hart_if.state.mstatus.UPIE << 27; - break; - default: - val |= clic_mprev_lvl << 16; - val |= hart_if.state.mstatus.MPIE << 27; - val |= hart_if.state.mstatus.MPP << 28; - break; - } - } else - val = hart_if.csr[addr] & ((1UL << (sizeof(WORD_TYPE) * 8 - 1)) | (hart_if.mcause_max_irq - 1)); - return iss::Ok; -} - -template iss::status clic::write_cause(unsigned addr, reg_t val) { - if((hart_if.csr[arch::mtvec] & 0x3) == 3) { - auto mask = ((1UL << (sizeof(WORD_TYPE) * 8 - 1)) | (hart_if.mcause_max_irq - 1) | (0xfUL << 16)); - hart_if.csr[addr] = (val & mask) | (hart_if.csr[addr] & ~mask); - auto mode = (addr >> 8) & 0x3; - switch(mode) { - case 0: - clic_uprev_lvl = ((val >> 16) & 0xff) | (1 << (8 - cfg.clic_int_ctl_bits)) - 1; - hart_if.state.mstatus.UPIE = (val >> 27) & 0x1; - break; - default: - clic_mprev_lvl = ((val >> 16) & 0xff) | (1 << (8 - cfg.clic_int_ctl_bits)) - 1; - hart_if.state.mstatus.MPIE = (val >> 27) & 0x1; - hart_if.state.mstatus.MPP = (val >> 28) & 0x3; - break; - } - } else { - auto mask = ((1UL << (sizeof(WORD_TYPE) * 8 - 1)) | (hart_if.mcause_max_irq - 1)); - hart_if.csr[addr] = (val & mask) | (hart_if.csr[addr] & ~mask); - } - return iss::Ok; -} - -template iss::status clic::read_intstatus(unsigned addr, reg_t& val) { - auto mode = (addr >> 8) & 0x3; - val = clic_uact_lvl & 0xff; - if(mode == 0x3) - val += (clic_mact_lvl & 0xff) << 24; - return iss::Ok; -} - -template iss::status clic::write_intthresh(unsigned addr, reg_t val) { - hart_if.csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; - return iss::Ok; + return iss::NotSupported; } } // namespace mem } // namespace iss +#endif diff --git a/src/iss/mem/memory_if.cpp b/src/iss/mem/memory_if.cpp index 3a68bcf..7f590fc 100644 --- a/src/iss/mem/memory_if.cpp +++ b/src/iss/mem/memory_if.cpp @@ -53,8 +53,14 @@ void memory_hierarchy::append(memory_elem& e) { hierarchy.push_back(&e); update_chain(); } -void memory_hierarchy::insert_before(memory_elem&) {} -void memory_hierarchy::insert_after(memory_elem&) {} +void memory_hierarchy::insert_before_last(memory_elem& e) { + hierarchy.insert(hierarchy.begin() + hierarchy.size() - 1, &e); + update_chain(); +} +void memory_hierarchy::insert_after_first(memory_elem& e) { + hierarchy.insert(hierarchy.begin() + 1, &e); + update_chain(); +} void memory_hierarchy::replace_last(memory_elem& e) { auto old = hierarchy.back(); auto it = std::find_if(std::begin(owned_elems), std::end(owned_elems), @@ -82,13 +88,13 @@ void memory_hierarchy::append(std::unique_ptr&& p) { owned_elems.push_back(std::move(p)); } -void memory_hierarchy::insert_before(std::unique_ptr&& p) { - insert_before(*p); +void memory_hierarchy::insert_before_last(std::unique_ptr&& p) { + insert_before_last(*p); owned_elems.push_back(std::move(p)); } -void memory_hierarchy::insert_after(std::unique_ptr&& p) { - insert_after(*p); +void memory_hierarchy::insert_after_first(std::unique_ptr&& p) { + insert_after_first(*p); owned_elems.push_back(std::move(p)); } diff --git a/src/iss/mem/memory_if.h b/src/iss/mem/memory_if.h index 8d6e8b7..4fc30af 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 { @@ -65,13 +65,13 @@ struct memory_hierarchy { void root(memory_elem&); void prepend(memory_elem&); void append(memory_elem&); - void insert_before(memory_elem&); - void insert_after(memory_elem&); + void insert_before_last(memory_elem&); + void insert_after_first(memory_elem&); void replace_last(memory_elem&); void prepend(std::unique_ptr&&); void append(std::unique_ptr&&); - void insert_before(std::unique_ptr&&); - void insert_after(std::unique_ptr&&); + void insert_before_last(std::unique_ptr&&); + void insert_after_first(std::unique_ptr&&); void replace_last(std::unique_ptr&&); protected: 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..0dc0b44 100644 --- a/src/iss/mem/mmu.h +++ b/src/iss/mem/mmu.h @@ -32,7 +32,11 @@ * eyck@minres.com - initial implementation ******************************************************************************/ +#ifndef ISS_MEM_MMU_H +#define ISS_MEM_MMU_H + #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 +72,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 +107,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 +232,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 +254,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) { @@ -318,3 +336,4 @@ template uint64_t mmu::virt2phys(iss::access_typ } } // namespace mem } // namespace iss +#endif diff --git a/src/iss/mem/pmp.h b/src/iss/mem/pmp.h index 6056c44..1501d03 100644 --- a/src/iss/mem/pmp.h +++ b/src/iss/mem/pmp.h @@ -30,78 +30,47 @@ * * Contributors: * eyck@minres.com - initial implementation + * cphurley82@gmail.com - bug fixes and improvements ******************************************************************************/ -#include "memory_if.h" +#ifndef ISS_MEM_PMP_H +#define ISS_MEM_PMP_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 { namespace mem { -struct clic_config { - uint64_t clic_base{0xc0000000}; - unsigned clic_int_ctl_bits{4}; - unsigned clic_num_irq{16}; - unsigned clic_num_trigger{0}; - bool nmode{false}; -}; - -inline void read_reg_with_offset(uint32_t reg, uint8_t offs, uint8_t* const data, unsigned length) { - auto reg_ptr = reinterpret_cast(®); - switch(offs) { - default: - for(auto i = 0U; i < length; ++i) - *(data + i) = *(reg_ptr + i); - break; - case 1: - for(auto i = 0U; i < length; ++i) - *(data + i) = *(reg_ptr + 1 + i); - break; - case 2: - for(auto i = 0U; i < length; ++i) - *(data + i) = *(reg_ptr + 2 + i); - break; - case 3: - *data = *(reg_ptr + 3); - break; - } -} - -inline void write_reg_with_offset(uint32_t& reg, uint8_t offs, const uint8_t* const data, unsigned length) { - auto reg_ptr = reinterpret_cast(®); - switch(offs) { - default: - for(auto i = 0U; i < length; ++i) - *(reg_ptr + i) = *(data + i); - break; - case 1: - for(auto i = 0U; i < length; ++i) - *(reg_ptr + 1 + i) = *(data + i); - break; - case 2: - for(auto i = 0U; i < length; ++i) - *(reg_ptr + 2 + i) = *(data + i); - break; - case 3: - *(reg_ptr + 3) = *data; - break; - } -} -template struct pmp : public memory_elem { - using this_class = pmp; - using reg_t = WORD_TYPE; - constexpr static unsigned WORD_LEN = sizeof(WORD_TYPE) * 8; - - pmp(arch::priv_if hart_if) +template struct pmp : public memory_elem { + static_assert(NUM_ENTRIES > 0 && NUM_ENTRIES <= 64 && (NUM_ENTRIES % sizeof(typename PLAT::reg_t)) == 0, + "NUM_ENTRIES must be a multiple of sizeof(reg_t) and at most 64"); + using this_class = pmp; + using reg_t = typename PLAT::reg_t; + static constexpr auto cfg_reg_size = sizeof(reg_t); + static constexpr reg_t cfg_valid_mask = sizeof(reg_t) == 8 ? reg_t(0x9f9f9f9f9f9f9f9fULL) : reg_t(0x9f9f9f9fU); + static constexpr size_t pmpcfg_stride = cfg_reg_size / 4; // 1 for RV32, 2 for RV64 + static constexpr auto PMP_SHIFT = 2U; + static constexpr auto PMP_R = 0x1U; + static constexpr auto PMP_W = 0x2U; + static constexpr auto PMP_X = 0x4U; + static constexpr auto PMP_A = 0x18U; + static constexpr auto PMP_L = 0x80U; + static constexpr auto PMP_TOR = 0x1U; + static constexpr auto PMP_NA4 = 0x2U; + static constexpr auto PMP_NAPOT = 0x3U; + + 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); - hart_if.csr_wr_cb[i] = MK_CSR_WR_CB(write_plain); + for(size_t i = arch::pmpaddr0; i < arch::pmpaddr0 + NUM_ENTRIES; ++i) { + hart_if.csr_rd_cb[i] = MK_CSR_RD_CB(read_pmpaddr); + hart_if.csr_wr_cb[i] = MK_CSR_WR_CB(write_pmpaddr); } - for(size_t i = arch::pmpcfg0; i < arch::pmpcfg0 + 16 / sizeof(reg_t); ++i) { - hart_if.csr_rd_cb[i] = MK_CSR_RD_CB(read_plain); + for(size_t i = arch::pmpcfg0; i < arch::pmpcfg0 + (NUM_ENTRIES / cfg_reg_size) * pmpcfg_stride; i += pmpcfg_stride) { + hart_if.csr_rd_cb[i] = MK_CSR_RD_CB(read_pmpcfg); hart_if.csr_wr_cb[i] = MK_CSR_WR_CB(write_pmpcfg); } } @@ -116,82 +85,96 @@ 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)) { - 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 + std::array pmpaddr{0}; + std::array pmpcfg{0}; + + 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 || std::numeric_limits::max()) && + !pmp_check(addr.access, addr.val, length) && !is_debug(addr.access)) { + if(is_debug(addr.access)) + throw trap_access(0, addr.val); + hart_if.raise_trap(/*trap_id*/ 0, /*cause*/ (addr.access == access_type::FETCH) ? 1 : 5, /*fault_data*/ addr.val); 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)) { - hart_if.fault_data = addr; - if(is_debug(access)) - throw trap_access(0, addr); - hart_if.reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 1 + 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)) { + if(is_debug(addr.access)) + throw trap_access(0, addr.val); + hart_if.raise_trap(/*trap_id*/ 0, /*cause*/ 7, /*fault_data*/ addr.val); 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) { - val = hart_if.csr[addr]; - return iss::Ok; + iss::status read_pmpaddr(unsigned addr, reg_t& val) { + if(addr >= arch::pmpaddr0 && addr < arch::pmpaddr0 + NUM_ENTRIES) { + val = pmpaddr[addr - arch::pmpaddr0]; + return iss::Ok; + } + return iss::Err; } - iss::status write_plain(unsigned addr, reg_t const& val) { - hart_if.csr[addr] = val; - return iss::Ok; + iss::status write_pmpaddr(unsigned addr, reg_t const& val) { + if(addr >= arch::pmpaddr0 && addr < arch::pmpaddr0 + NUM_ENTRIES) { + pmpaddr[addr - arch::pmpaddr0] = val; + return iss::Ok; + } + return iss::Err; } + iss::status read_pmpcfg(unsigned addr, reg_t& val) { + if(addr >= arch::pmpcfg0 && addr < arch::pmpcfg0 + (NUM_ENTRIES / cfg_reg_size) * pmpcfg_stride) { + val = pmpcfg[(addr - arch::pmpcfg0) / pmpcfg_stride]; + return iss::Ok; + } + return iss::Err; + } iss::status write_pmpcfg(unsigned addr, reg_t val) { - hart_if.csr[addr] = val & 0x9f9f9f9f; - return iss::Ok; + if(addr >= arch::pmpcfg0 && addr < arch::pmpcfg0 + (NUM_ENTRIES / cfg_reg_size) * pmpcfg_stride) { + pmpcfg[(addr - arch::pmpcfg0) / pmpcfg_stride] = val & cfg_valid_mask; + any_active = false; + for(size_t i = 0; i < NUM_ENTRIES; i++) { + auto cfg = pmpcfg[i / cfg_reg_size] >> ((i % cfg_reg_size) * 8); + any_active |= cfg & PMP_A; + } + return iss::Ok; + } + return iss::Err; } - bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); + bool pmp_check(access_type type, uint64_t addr, unsigned len); protected: - arch::priv_if hart_if; + bool any_active = false; + 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) { - constexpr auto PMP_SHIFT = 2U; - constexpr auto PMP_R = 0x1U; - constexpr auto PMP_W = 0x2U; - constexpr auto PMP_X = 0x4U; - constexpr auto PMP_A = 0x18U; - constexpr auto PMP_L = 0x80U; - constexpr auto PMP_TOR = 0x1U; - constexpr auto PMP_NA4 = 0x2U; - constexpr auto PMP_NAPOT = 0x3U; +template bool pmp::pmp_check(access_type type, uint64_t addr, unsigned len) { + if(!any_active) + return true; reg_t base = 0; - auto any_active = false; - auto const cfg_reg_size = sizeof(reg_t); - for(size_t i = 0; i < 16; i++) { - reg_t tor = hart_if.csr[arch::pmpaddr0 + i] << PMP_SHIFT; - uint8_t cfg = hart_if.csr[arch::pmpcfg0 + (i / cfg_reg_size)] >> (i % cfg_reg_size); + for(size_t i = 0; i < NUM_ENTRIES; i++) { + reg_t tor = pmpaddr[i] << PMP_SHIFT; + reg_t cfg = pmpcfg[i / cfg_reg_size] >> ((i % cfg_reg_size) * 8); if(cfg & PMP_A) { - any_active = true; auto pmp_a = (cfg & PMP_A) >> 3; auto is_tor = pmp_a == PMP_TOR; auto is_na4 = pmp_a == PMP_NA4; - - reg_t mask = (hart_if.csr[arch::pmpaddr0 + i] << 1) | (!is_na4); + reg_t mask = (pmpaddr[i] << 1) | (!is_na4); mask = ~(mask & ~(mask + 1)) << PMP_SHIFT; - // Check each 4-byte sector of the access auto any_match = false; auto all_match = true; for(reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) { reg_t cur_addr = addr + offset; auto napot_match = ((cur_addr ^ tor) & mask) == 0; - auto tor_match = base <= (cur_addr + len - 1) && cur_addr < tor; + auto tor_match = base <= cur_addr && cur_addr < tor; auto match = is_tor ? tor_match : napot_match; any_match |= match; all_match &= match; @@ -200,7 +183,7 @@ template bool pmp::pmp_check(const access_type t // If the PMP matches only a strict subset of the access, fail it if(!all_match) return false; - return (hart_if.reg.PRIV == arch::PRIV_M && !(cfg & PMP_L)) || (type == access_type::READ && (cfg & PMP_R)) || + return (hart_if.PRIV == arch::PRIV_M && !(cfg & PMP_L)) || (type == access_type::READ && (cfg & PMP_R)) || (type == access_type::WRITE && (cfg & PMP_W)) || (type == access_type::FETCH && (cfg & PMP_X)); } } @@ -237,8 +220,9 @@ template bool pmp::pmp_check(const access_type t // } // tor_base = pmpaddr; // } - return !any_active || hart_if.reg.PRIV == arch::PRIV_M; + return hart_if.PRIV == arch::PRIV_M; } } // namespace mem } // namespace iss +#endif diff --git a/src/iss/arch/wt_cache.h b/src/iss/mem/wt_cache.h similarity index 79% rename from src/iss/arch/wt_cache.h rename to src/iss/mem/wt_cache.h index 9b6a9fb..410d61f 100644 --- a/src/iss/arch/wt_cache.h +++ b/src/iss/mem/wt_cache.h @@ -35,6 +35,7 @@ #ifndef _RISCV_HART_M_P_WT_CACHE_H #define _RISCV_HART_M_P_WT_CACHE_H +#include "iss/arch/riscv_hart_common.h" #include #include #include @@ -42,7 +43,7 @@ #include namespace iss { -namespace arch { +namespace mem { namespace cache { enum class state { INVALID, VALID }; @@ -74,17 +75,23 @@ struct wt_policy { } // namespace cache // write thru, allocate on read, direct mapped or set-associative with round-robin replacement policy -template class wt_cache : public BASE { +template class wt_cache : public PLAT { public: - using base_class = BASE; - using this_class = wt_cache; - using reg_t = typename BASE::reg_t; - using mem_read_f = typename BASE::mem_read_f; - using mem_write_f = typename BASE::mem_write_f; - using phys_addr_t = typename BASE::phys_addr_t; - - wt_cache(feature_config cfg = feature_config{}); + using base_class = PLAT; + using this_class = wt_cache; + using reg_t = typename PLAT::reg_t; + using mem_read_f = typename PLAT::mem_read_f; + using mem_write_f = typename PLAT::mem_write_f; + using phys_addr_t = typename PLAT::phys_addr_t; + + wt_cache(arch::priv_if hart_if); virtual ~wt_cache() = default; + memory_if get_mem_if() override { + return memory_if{.rd_mem{util::delegate::from(this)}, + .wr_mem{util::delegate::from(this)}}; + } + + void set_next(memory_if mem) override { down_stream_mem = mem; } unsigned size{4096}; unsigned line_sz{64}; @@ -93,28 +100,26 @@ template class wt_cache : public BASE { uint64_t io_addr_mask{0xf0000000}; protected: - iss::status read_cache(phys_addr_t addr, unsigned, uint8_t* const); - iss::status write_cache(phys_addr_t addr, unsigned, uint8_t const* const); - std::function cache_mem_rd_delegate; - std::function cache_mem_wr_delegate; + iss::status read_cache(addr_t addr, unsigned, uint8_t* const); + iss::status write_cache(addr_t addr, unsigned, uint8_t const* const); + arch::priv_if hart_if; + memory_if down_stream_mem; std::unique_ptr dcache_ptr; std::unique_ptr icache_ptr; size_t get_way_select() { return 0; } }; -template -inline wt_cache::wt_cache(feature_config cfg) -: BASE(cfg) +template +inline wt_cache::wt_cache(arch::priv_if hart_if) +: hart_if(hart_if) , io_address{cfg.io_address} , io_addr_mask{cfg.io_addr_mask} { auto cb = base_class::replace_mem_access( [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return read_cache(a, l, d); }, [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return write_cache(a, l, d); }); - cache_mem_rd_delegate = cb.first; - cache_mem_wr_delegate = cb.second; } -template iss::status iss::arch::wt_cache::read_cache(phys_addr_t a, unsigned l, uint8_t* const d) { +template iss::status wt_cache::read_cache(addr_t a, unsigned l, uint8_t* const d) { if(!icache_ptr) { icache_ptr.reset(new cache::cache(size, line_sz, ways)); dcache_ptr.reset(new cache::cache(size, line_sz, ways)); @@ -142,13 +147,13 @@ template iss::status iss::arch::wt_cache::read_cache(phys_ d[i] = cl.data[start_addr + i]; return iss::Ok; } else - return cache_mem_rd_delegate(a, l, d); + return down_stream_mem.rd_mem(addr, length, data); } -template iss::status iss::arch::wt_cache::write_cache(phys_addr_t a, unsigned l, const uint8_t* const d) { +template iss::status wt_cache::write_cache(addr_t a, unsigned l, const uint8_t* const d) { if(!dcache_ptr) dcache_ptr.reset(new cache::cache(size, line_sz, ways)); - auto res = cache_mem_wr_delegate(a, l, d); + auto res = down_stream_mem.wr_mem(addr, length, data); if(res == iss::Ok && ((a.val & io_addr_mask) != io_address)) { auto set_addr = (a.val & (size - 1)) >> util::ilog2(line_sz * ways); auto tag_addr = a.val >> util::ilog2(line_sz); @@ -165,7 +170,7 @@ template iss::status iss::arch::wt_cache::write_cache(phys return res; } -} // namespace arch +} // namespace mem } // namespace iss #endif /* _RISCV_HART_M_P_H */ diff --git a/src/iss/semihosting/semihosting.cpp b/src/iss/semihosting/semihosting.cpp index 21fe0c4..368eec2 100644 --- a/src/iss/semihosting/semihosting.cpp +++ b/src/iss/semihosting/semihosting.cpp @@ -33,6 +33,9 @@ ******************************************************************************/ #include "semihosting.h" +#include +#include +#include #include #include #include @@ -42,16 +45,16 @@ const char* SYS_OPEN_MODES_STRS[] = {"r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b"}; -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::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character); - - if(res != iss::Ok) { +template T sh_read_field(iss::arch_if* arch_if_ptr, T addr, size_t len = sizeof(T)) { + std::array bytes{}; + len = std::min(len, sizeof(T)); + auto res = arch_if_ptr->read({iss::address_type::LOGICAL, iss::access_type::DEBUG_READ, 0, addr}, len, bytes.data()); + if(res != iss::Ok) return 0; // TODO THROW ERROR - } else - return static_cast(bytes[0]) | (static_cast(bytes[1]) << 8) | (static_cast(bytes[2]) << 16) | - (static_cast(bytes[3]) << 24); + T value{0}; + for(size_t i = 0; i < len; ++i) + value |= static_cast(bytes[i]) << (8 * i); + return value; } template std::string sh_read_string(iss::arch_if* arch_if_ptr, T addr, T str_len) { @@ -67,6 +70,16 @@ template void semihosting_callback::operator()(iss::arch_if* arc static std::map openFiles; static T file_count = 3; static T semihostingErrno; + auto get_open_file = [call_number, this](T file_handle, FILE*& file) -> bool { + auto it = openFiles.find(file_handle); + if(it == openFiles.end() || it->second == nullptr) { + semihostingErrno = EBADF; + *call_number = static_cast(-1); + return false; + } + file = it->second; + return true; + }; switch(static_cast(*call_number)) { case semihosting_syscalls::SYS_CLOCK: { @@ -78,11 +91,13 @@ template void semihosting_callback::operator()(iss::arch_if* arc } case semihosting_syscalls::SYS_CLOSE: { T file_handle = *parameter; - if(openFiles.size() <= file_handle && file_handle < 0) { + auto it = openFiles.find(file_handle); + if(it == openFiles.end() || it->second == nullptr) { semihostingErrno = EBADF; + *call_number = static_cast(-1); return; } - auto file = openFiles[file_handle]; + auto file = it->second; openFiles.erase(file_handle); if(!(file == stdin || file == stdout || file == stderr)) { int i = fclose(file); @@ -112,7 +127,9 @@ template void semihosting_callback::operator()(iss::arch_if* arc } case semihosting_syscalls::SYS_FLEN: { T file_handle = *parameter; - auto file = openFiles[file_handle]; + FILE* file = nullptr; + if(!get_open_file(file_handle, file)) + return; size_t currentPos = ftell(file); if(currentPos < 0) @@ -151,7 +168,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc // TODO LOG INFO if(mode >= 12) { - // TODO throw ERROR + *call_number = static_cast(-1); return; } @@ -166,7 +183,7 @@ template void semihosting_callback::operator()(iss::arch_if* arc } else { file = fopen(path_str.c_str(), SYS_OPEN_MODES_STRS[mode]); if(file == nullptr) { - // TODO throw error + *call_number = static_cast(-1); return; } } @@ -179,8 +196,9 @@ template void semihosting_callback::operator()(iss::arch_if* arc T file_handle = sh_read_field(arch_if_ptr, (*parameter) + 4); T addr = sh_read_field(arch_if_ptr, *parameter); T count = sh_read_field(arch_if_ptr, (*parameter) + 8); - - auto file = openFiles[file_handle]; + FILE* file = nullptr; + if(!get_open_file(file_handle, file)) + return; std::vector buffer(count); size_t num_read = 0; @@ -199,7 +217,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_WRITE, 0, addr + i}, 1, &buffer[i]); if(res != iss::Ok) return; } @@ -238,7 +256,9 @@ template void semihosting_callback::operator()(iss::arch_if* arc case semihosting_syscalls::SYS_SEEK: { T file_handle = sh_read_field(arch_if_ptr, *parameter); T pos = sh_read_field(arch_if_ptr, (*parameter) + 1); - auto file = openFiles[file_handle]; + FILE* file = nullptr; + if(!get_open_file(file_handle, file)) + return; int retval = fseek(file, pos, SEEK_SET); if(retval < 0) @@ -275,9 +295,9 @@ template void semihosting_callback::operator()(iss::arch_if* arc ss << "tmp/file-" << std::setfill('0') << std::setw(3) << identifier; std::string filename = ss.str(); - for(int i = 0; i < buffer_len; i++) { + for(int i = 0; i < buffer_len && i < static_cast(filename.size()); 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_WRITE, 0, (*parameter) + i}, 1, &character); if(res != iss::Ok) return; } @@ -287,15 +307,16 @@ template void semihosting_callback::operator()(iss::arch_if* arc T file_handle = sh_read_field(arch_if_ptr, (*parameter) + 4); T addr = sh_read_field(arch_if_ptr, *parameter); T count = sh_read_field(arch_if_ptr, (*parameter) + 8); - - auto file = openFiles[file_handle]; + FILE* file = nullptr; + if(!get_open_file(file_handle, file)) + return; std::string str = sh_read_string(arch_if_ptr, addr, count); fwrite(&str[0], 1, count, file); break; } 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 +325,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..d78b83d 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; @@ -144,16 +147,10 @@ int main(int argc, char* argv[]) { } return 0; } else if(isa_opt.find(':') == std::string::npos) { + if(isa_opt == "tgc5d" || isa_opt == "tgc5e") + isa_opt += "_clic_pmp"; std::tie(cpu, vm) = f.create(isa_opt + ":" + clim["backend"].as(), clim["gdb-port"].as(), &semihosting_cb); - } else { - auto base_isa = isa_opt.substr(0, 5); - if(base_isa == "tgc5d" || base_isa == "tgc5e") { - isa_opt += "_clic_pmp:" + clim["backend"].as(); - } else { - isa_opt += ":" + clim["backend"].as(); - } - std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as(), &semihosting_cb); } if(!cpu) { auto list = f.get_names(); @@ -207,7 +204,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 +269,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 353bb81..b3cd825 100644 --- a/src/sysc/core2sc_adapter.h +++ b/src/sysc/core2sc_adapter.h @@ -35,8 +35,10 @@ #ifndef _SYSC_CORE2SC_ADAPTER_H_ #define _SYSC_CORE2SC_ADAPTER_H_ -#include "core_complex_if.h" +#include "iss/arch_if.h" #include "sc2core_if.h" +#include "util/delegate.h" +#include "util/logging.h" #include #include #include @@ -45,6 +47,8 @@ #include #include #include +#include +#include #include namespace sysc { @@ -62,7 +66,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if this->csr_rd_cb[iss::arch::timeh] = MK_CSR_RD_CB(read_time); this->memories.replace_last(*this); this->set_hartid = util::delegate::from(this); - this->set_irq_count = util::delegate::from(this); + this->get_arch_if = 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); @@ -70,11 +74,15 @@ 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); + + 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_arch_if = 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); @@ -86,6 +94,20 @@ template class core2sc_adapter : public PLAT, public sc2core_if virtual ~core2sc_adapter() {} + void enable_disass(bool enable) override { + if(enable) + this->disass_func = + util::delegate::from(this); + else + this->disass_func = util::delegate::from(this); + } + + void set_clint_irq_count(size_t num) override { this->set_clint_irq_num(num); } + + 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(); @@ -98,35 +120,80 @@ 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 record_n_print_disass(uint64_t pc, std::string const& str, bool printpc) { + if(!printpc) + owner->disass_output(pc, str); + static CONSTEXPR char const* fmt_str = sizeof(reg_t) == 4 ? "[disass] 0x{:08x} {:40} [p:{};s:0x{:02x};i:{};c:{}]" + : "[disass] 0x{:012x} {:40} [p:{};s:0x{:04x};i:{};c:{}]"; + if(printpc) { + SCCINFO(owner->hier_name()) << fmt::format(fmt_str, pc, str, this->lvl[this->reg.PRIV], (reg_t)this->state.mstatus, + this->reg.icount, this->reg.cycle + this->cycle_offset); + } else { + SCCINFO(owner->hier_name()) << "[disass] " << str; + } + }; + void no_disass(uint64_t pc, std::string const& str, bool printpc) { return; }; iss::mem::memory_if get_mem_if() { return iss::mem::memory_if{.rd_mem{util::delegate::from(this)}, .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; @@ -148,7 +215,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) { @@ -186,10 +254,30 @@ template class core2sc_adapter : public PLAT, public sc2core_if } void wait_until(uint64_t flags) { - SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt"; + // check if WFI is allowed 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.event()); + if(this->reg.trap_state) + return; + // now wait until something is happening + SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt"; + wfi_inst.store(true, std::memory_order_relaxed); + std::function f = [this]() { + while((this->mip_csr & this->mie_csr) == 0) { + sc_core::wait(this->wfi_evt | this->debugger_stop_evt); + bool is_debugger_stop_evt = this->debugger_stop_evt.triggered(); + if(is_debugger_stop_evt) + break; + } + SCCINFO(this->owner->hier_name()) << "Got WFI event"; + }; + owner->exec_on_sysc(f); + wfi_inst.store(false, std::memory_order_relaxed); + } + + void cancel_wait() { + if(wfi_inst.load(std::memory_order_relaxed) == true) { + SCCDEBUG(owner->hier_name()) << "Trigger debugger stop event"; + this->debugger_stop_evt.notify(sc_core::SC_ZERO_TIME); } } @@ -200,11 +288,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if 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); - } + iss::arch_if* _get_arch_if() { return this; } uint32_t _get_mode() { return this->reg.PRIV; } uint32_t _get_mode_mt() { @@ -231,37 +315,36 @@ template class core2sc_adapter : public PLAT, public sc2core_if } 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; + uint64_t mask = 0; + if(sizeof(reg_t) == 4) { + assert(id < 32 && "CLINT cannot handle more than 32 irq"); + } else { + assert(id < 64 && "CLINT cannot handle more than 64 irq"); } + mask = 1 << id; if(value) { - this->csr[iss::arch::mip] |= mask; + this->mip_csr |= mask; wfi_evt.notify(); } else - this->csr[iss::arch::mip] &= ~mask; + this->mip_csr &= ~mask; this->check_interrupt(); if(value) - SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; + SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id +#ifndef NDEBUG + << " (Pending trap: " << std::hex << "0x" + << ((this->reg.pending_trap >> 16) & 0xff) // 0x80 << 24 | (cause << 16) | trap_id + << ")" +#endif + ; } + 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); @@ -276,6 +359,7 @@ template class core2sc_adapter : public PLAT, public sc2core_if } 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); } @@ -285,9 +369,12 @@ template class core2sc_adapter : public PLAT, public sc2core_if } sysc::riscv::core_complex_if* const owner{nullptr}; - scc::async_event wfi_evt; + util::LoggerDelegate log_delegate; + sc_core::sc_event wfi_evt; + sc_core::sc_event debugger_stop_evt; unsigned to_host_wr_cnt = 0; bool first{true}; + std::atomic wfi_inst{false}; mutex_t sync_mtx; }; } // namespace sysc diff --git a/src/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index 9ce5f92..00e7414 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -39,8 +39,13 @@ #include #include #include "iss_factory.h" +#include "sysc/memspace_extension.h" +#include +#include +#include #include #include +#include #include #ifndef WIN32 #include @@ -51,6 +56,7 @@ #include #include #include +#include // clang-format on #ifdef HAS_SCV @@ -82,11 +88,15 @@ using namespace sc_core; namespace { iss::debugger::encoder_decoder encdec; std::array lvl = {{'U', 'S', 'H', 'M'}}; + +inline bool is_in_end_range(uint64_t end, uint64_t inclusive_range_end) { + return (end <= inclusive_range_end) || ((end >= 0) && ((end - 1) <= inclusive_range_end)); +} } // 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(); @@ -115,17 +125,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; @@ -144,7 +152,6 @@ void core_complex::create_cpu(std::string const& type, std::string con os << " backend " << e.first << ":\n - " << util::join(e.second, "\n - "); } SCCINFO(SCMOD) << "\n" << os.str(); - sc_core::sc_stop(); } else if(type.find(':') == std::string::npos) { std::tie(core, vm) = f.create(type + ":" + backend, gdb_port, this); } else { @@ -163,6 +170,7 @@ void core_complex::create_cpu(std::string const& type, std::string con SCCFATAL() << "Could not create vm for isa " << type << " and backend " << backend; } else { core->set_hartid(hart_id); + core->set_clint_irq_count(clint_irq_i.size()); auto* srv = debugger::server::get(); if(srv) tgt_adapter = srv->get_target(0); // FIXME: add core_id @@ -176,68 +184,57 @@ 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()) { - init(); +template +core_complex::core_complex(sc_module_name const& name, size_t clint_irq_size) +: sc_module(name) { + init(clint_irq_size); } #endif -template void core_complex::init() { +template void core_complex::init(size_t clint_irq_size) { + 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) { + if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && is_in_end_range(end, lut_entry.get_end_address())) { fetch_lut.removeEntry(lut_entry); } }); 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 && is_in_end_range(end, lut_entry.get_end_address())) { + 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 && is_in_end_range(end, lut_entry.get_end_address())) { + write_lut.removeEntry(lut_entry); + } } }); - SC_HAS_PROCESS(core_complex); // NOLINT + clint_irq_i.init(clint_irq_size); + 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(); +#if SC_VERSION_MAJOR > 2 + sensitive << clint_irq_i; +#else + for(auto& s : clint_irq_i) + sensitive << s; +#endif #endif - trc.m_db = scv_tr_db::get_default_db(); SC_METHOD(forward); #ifndef CWR_SYSTEMC @@ -250,30 +247,32 @@ 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); + SCCDEBUG(SCMOD) << "instantiating hart" << GET_PROP_VALUE(mhartid) << " " << type << " with " << GET_PROP_VALUE(backend) << " backend"; create_cpu(type, GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid)); - if(type == "?") + if(type != "?" && (!core || !vm)) { + SCCFATAL(SCOBJ) << "Could not create core " << type; return; -#ifndef CWR_SYSTEMC - if(!local_irq_num.is_default_value()) { - core->set_irq_count(16 + local_irq_num); } -#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) { @@ -308,14 +307,17 @@ 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(!core) { + sc_core::sc_stop(); + return; + } if(GET_PROP_VALUE(elf_file).size() > 0) { auto file_names = util::split(GET_PROP_VALUE(elf_file), ','); for(auto& s : file_names) { std::pair load_result = load_file(s); if(!std::get<1>(load_result)) { - SCCWARN(SCMOD) << "Could not load FW file " << s; + SCCERR(SCMOD) << "Could not load FW file " << s; } else { #ifndef CWR_SYSTEMC if(reset_address.is_default_value()) @@ -327,28 +329,17 @@ 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); + if(GET_PROP_VALUE(show_memory_map)) { + auto result = tlm::scc::gather_memory(dbus.get_base_port()); + SCCINFO(SCOBJ) << "DBUS memory map:\n" << result.to_string(); } } -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 @@ -357,80 +348,92 @@ 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); if(rst_i.read()) { reset(GET_PROP_VALUE(reset_address)); wait(rst_i.negedge_event()); + reset(GET_PROP_VALUE(reset_address)); // in case it has changed during reset } 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 && is_in_end_range(addr.val + length, lut_entry.get_end_address())) { + 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 + SCCTRACEALL(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 { @@ -440,19 +443,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() && is_in_end_range(addr.val + length, 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); } } @@ -460,79 +462,109 @@ 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 && is_in_end_range(addr.val + length, lut_entry.get_end_address())) { + 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 + SCCTRACEALL(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() && is_in_end_range(addr.val + length, 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_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>; - +#if SC_VERSION_MAJOR > 2 +template class core_complex; +template class core_complex<32, tlm::scc::quantumkeeper_mt>; +template class core_complex<64, tlm::scc::quantumkeeper_mt>; +#endif } // namespace riscv } /* namespace sysc */ diff --git a/src/sysc/core_complex.h b/src/sysc/core_complex.h index ac4f01b..5f5019b 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, LOCAL_IRQ_START = 16 }; + +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"}; #ifndef CWR_SYSTEMC sc_core::sc_in clk_i{"clk_i"}; @@ -103,10 +106,14 @@ 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}; + cci::cci_param finish_condition{"finish_condition", static_cast(iss::finish_cond_e::NONE)}; + cci::cci_param core_type{"core_type", "rv32imac_m"}; cci::cci_param backend{"backend", "interp"}; @@ -115,13 +122,15 @@ template class core_complex : public sc_core:: cci::cci_param dump_ir{"dump_ir", false}; - cci::cci_param mhartid{"mhartid", 0}; + cci::cci_param show_memory_map{"show_memory_map", false}; - cci::cci_param local_irq_num{"local_irq_num", 0}; + cci::cci_param mhartid{"mhartid", 0}; cci::cci_param plugins{"plugins", ""}; - core_complex(sc_core::sc_module_name const& name); + cci::cci_param post_run_stats{"post_run_stats", false}; + + core_complex(sc_core::sc_module_name const& name, size_t clint_irq_size = 32); #else sc_core::sc_in clk_i{"clk_i"}; @@ -142,11 +151,15 @@ template class core_complex : public sc_core:: scml_property dump_ir{"dump_ir", false}; + scml_property show_memory_map{"show_memory_map", false}; + scml_property mhartid{"mhartid", 0}; scml_property plugins{"plugins", ""}; - core_complex(sc_core::sc_module_name const& name) + scml_property post_run_stats{"post_run_stats", false}; + + core_complex(sc_core::sc_module_name const& name, size_t clint_irq_size = 32) : sc_module(name) , local_irq_i{"local_irq_i", 16} , elf_file{"elf_file", ""} @@ -157,11 +170,8 @@ template class core_complex : public sc_core:: , gdb_server_port{"gdb_server_port", 0} , dump_ir{"dump_ir", false} , mhartid{"mhartid", 0} - , plugins{"plugins", ""} - , fetch_lut(tlm_dmi_ext()) - , read_lut(tlm_dmi_ext()) - , write_lut(tlm_dmi_ext()) { - init(); + , plugins{"plugins", ""} { + init(clint_irq_size); } #endif @@ -176,25 +186,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 +208,125 @@ 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; + } + + void register_csr_rd(unsigned csr_addr, sc2core_if::rd_csr_f& func) { + assert(core != nullptr); + core->register_csr_rd(csr_addr, func); + } + + void register_csr_wr(unsigned csr_addr, sc2core_if::wr_csr_f& func) { + assert(core != nullptr); + core->register_csr_wr(csr_addr, func); + } + + void register_unknown_instr_handler(util::delegate handler) { + assert(core != nullptr); + core->register_unknown_instr_handler(handler); + } + 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 +#if SC_VERSION_MAJOR > 2 + /////////////////////////////////////////////////////////////////////////////// + // 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) { + 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) { + 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, static_cast(finish_condition.get_value())); + return quantum_keeper.get_local_absolute_time(); + }); + } #endif + /////////////////////////////////////////////////////////////////////////////// + // 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) { + return dbus->get_direct_mem_ptr(gp, dmi_data); + } + 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, static_cast(finish_condition.get_value())); + } + /////////////////////////////////////////////////////////////////////////////// + // + /////////////////////////////////////////////////////////////////////////////// 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()}; + util::range_lut& get_read_lut(unsigned space) { + return space < dmi_read_luts.size() ? dmi_read_luts[space] : get_lut(dmi_read_luts, space); + }; + util::range_lut& get_write_lut(unsigned space) { + return space < dmi_write_luts.size() ? dmi_write_luts[space] : get_lut(dmi_write_luts, 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(); + void init(size_t clint_irq_size); + // 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..6eff667 100644 --- a/src/sysc/core_complex_if.h +++ b/src/sysc/core_complex_if.h @@ -33,7 +33,10 @@ #ifndef _SYSC_CORE_COMPLEX__IF_H_ #define _SYSC_CORE_COMPLEX__IF_H_ +#include +#include #include +#include namespace sysc { namespace riscv { @@ -41,21 +44,27 @@ 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 iss::mem::clic_config get_clic_config() { + return iss::mem::clic_config{.clic_base = 0, .clic_int_ctl_bits = 0, .clic_num_irq = 0, .clic_num_trigger = 0, .nmode = false}; + } - virtual bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) = 0; + virtual bool read_mem(const iss::addr_t& addr, unsigned length, uint8_t* const data) = 0; - virtual bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) = 0; + virtual bool write_mem(const iss::addr_t& addr, unsigned length, const uint8_t* const data) = 0; - virtual bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) = 0; + virtual bool read_mem_dbg(const iss::addr_t& addr, unsigned length, uint8_t* const data) = 0; - virtual bool disass_output(uint64_t pc, const std::string instr) = 0; + virtual bool write_mem_dbg(const iss::addr_t& addr, unsigned length, const uint8_t* const data) = 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/core_complex_mt.cpp b/src/sysc/core_complex_mt.cpp deleted file mode 100644 index d0b93fd..0000000 --- a/src/sysc/core_complex_mt.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2017, 2018 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. - * - *******************************************************************************/ - -// clang-format off -#include "core_complex_mt.h" -#include -#include -#include -#include -#include -#include -#include -#include "iss_factory.h" -#include -#include -#include -#include -#include -#ifndef WIN32 -#include -#endif -#include -#include -#include -#include -#include -#include -// clang-format on - -#ifdef HAS_SCV -#include -#else -#include -using namespace scv_tr; -#endif - -#define GET_PROP_VALUE(P) P.get_value() - -#ifdef _MSC_VER -// not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif - -namespace sysc { -namespace riscv { -using namespace std; -using namespace iss; -using namespace logging; -using namespace sc_core; - -namespace { -iss::debugger::encoder_decoder encdec; -std::array lvl = {{'U', 'S', 'H', 'M'}}; -} // namespace - -template -int core_complex_mt::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(); - of(t.c_str()); - std::array buf; - encdec.enc_string(t.c_str(), buf.data(), 63); - df(buf.data()); - return Ok; - } else if(strcasecmp(argv[1], "break") == 0) { - sc_time t; - if(argc == 4) { - t = scc::parse_from_string(argv[2], argv[3]); - } else if(argc == 3) { - t = scc::parse_from_string(argv[2]); - } else - return Err; - // no check needed as it is only called if debug server is active - tgt_adapter->add_break_condition([t]() -> unsigned { - SCCTRACE() << "Checking condition at " << sc_time_stamp(); - return sc_time_stamp() >= t ? std::numeric_limits::max() : 0; - }); - return Ok; - } - return Err; - } - return Err; -} - -template void core_complex_mt::reset(uint64_t addr) { vm->reset(addr); } - -template inline std::pair core_complex_mt::load_file(std::string const& name) { - iss::arch_if* cc = vm->get_arch(); - return cc->load_file(name); -}; - -template -void core_complex_mt::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; - for(auto& e : f.get_names()) { - auto p = e.find(':'); - assert(p != std::string::npos); - core_by_backend[e.substr(p + 1)].push_back(e.substr(0, p)); - } - std::ostringstream os; - os << "Available implementations\n"; - os << "=========================\n"; - for(auto& e : core_by_backend) { - std::sort(std::begin(e.second), std::end(e.second)); - if(os.str().size()) - os << "\n"; - os << " backend " << e.first << ":\n - " << util::join(e.second, "\n - "); - } - SCCINFO(SCMOD) << "\n" << os.str(); - sc_core::sc_stop(); - } else if(type.find(':') == std::string::npos) { - std::tie(core, vm) = f.create(type + ":" + backend, gdb_port, this); - } else { - auto base_isa = type.substr(0, 5); - if(base_isa == "tgc5d" || base_isa == "tgc5e") { - std::tie(core, vm) = f.create(type + "_clic_pmp:" + backend, gdb_port, this); - } else { - std::tie(core, vm) = f.create(type + ":" + backend, gdb_port, this); - } - } - if(!core) { - if(type != "?") - SCCFATAL() << "Could not create cpu for isa " << type << " and backend " << backend; - } else if(!vm) { - if(type != "?") - SCCFATAL() << "Could not create vm for isa " << type << " and backend " << backend; - } else { - core->set_hartid(hart_id); - auto* srv = debugger::server::get(); - if(srv) - tgt_adapter = srv->get_target(0); // FIXME: add core_id - if(tgt_adapter) - tgt_adapter->add_custom_command({"sysc", - [this](int argc, char* argv[], debugger::out_func of, debugger::data_func df) -> int { - return cmd_sysc(argc, argv, of, df, tgt_adapter); - }, - "SystemC sub-commands: break