101 Commits

Author SHA1 Message Date
c8679fca85 remove MSVC warning 2021-10-10 19:56:33 +02:00
f0ada1ba8c add MSVC 16 compatibility 2021-10-10 19:06:41 +02:00
09b01af3fa fix find_package use and debug access alignment check 2021-08-26 22:10:27 +02:00
9c8b72693e correct trap ids of access faults 2021-08-20 09:02:56 +02:00
c409e7b7ca adapt to fixed handling of SystemCPackage 2021-08-19 13:38:29 +02:00
2f05083cf0 fix elf loader and pmp check for debug accesses 2021-08-19 10:50:25 +02:00
e934049dd4 fix inconsistency due to PA adaptation 2021-08-16 17:55:14 +02:00
94f796ebdb add install target and PA compatibility 2021-08-16 17:02:31 +02:00
836ba269e3 fix clic reset values 2021-08-16 15:05:05 +02:00
c8681096be update vm_tgfs_c to match CoreDSL 2021-08-14 10:57:36 +02:00
adeffe47ad fix behavior of riscv_hart_mu_p to match TGC_D 2021-08-12 20:34:10 +02:00
d95846a849 fix trap handling if illegal fetch (PMP) and U-mode CSRs 2021-08-01 17:23:22 +02:00
af887c286f fix for #2 2021-07-28 09:09:08 +02:00
4ddf50162c make library naming consistent 2021-07-27 15:55:08 +02:00
da819d8890 fix SystemC lib handling in build system 2021-07-27 12:25:31 +02:00
5ef5d57d30 Merge branch 'tmp' into develop 2021-07-27 10:49:35 +02:00
d7bddd825c add clic CSRs 2021-07-27 10:47:48 +02:00
15f46a87db adapt core_complex to use scv-tr (scc commit id a3cde47) 2021-07-27 09:38:05 +02:00
fc1ae4d57d update build system 2021-07-26 12:03:52 +02:00
d0f3a120fd fix naming in MU wrapper 2021-07-19 16:26:23 +02:00
c592a26346 fix mepc mask 2021-07-09 13:01:22 +02:00
e68918c2e8 fix instruction decode 2021-07-09 07:37:12 +02:00
473f8a5a17 fix privilege behavior 2021-07-07 11:30:00 +02:00
2f4b5bd9b2 fix detailed behavior of TGC_C 2021-07-06 21:19:36 +02:00
23b9741adf refine and fix TGC_C iss to becoem compliant 2021-06-29 11:51:30 +02:00
5d8da08ce5 fix linker issue
the root cuase of the issue is the template paramter deduction which led
to the wrong template parameter.
2021-06-26 14:30:36 +02:00
a249aea703 getting rid of the error: reference to 'wait' is ambiguous 2021-06-25 13:35:42 +02:00
e432dd8208 fix handling of exceptions while accessing address spaces 2021-06-07 22:22:36 +02:00
8c385647dd remove redundant code from checked in generated sources 2021-05-26 23:06:31 +02:00
aaceecd5dc fix mu_p platform features and CSRs 2021-05-17 09:20:09 +02:00
4b3f5a6b0c add missing change 2021-05-16 16:44:30 +02:00
d41e1d816a add factory for ISS and use it in main.cpp 2021-05-16 16:44:14 +02:00
a35974c9f5 make cpu type in core_complex configurable 2021-05-16 15:06:42 +02:00
9c456ba8f2 initial version of MU hart 2021-05-14 13:29:39 +02:00
c57884caee small fix 2021-05-13 16:01:04 +02:00
cf7b62a3f9 update names 2021-05-13 15:54:48 +02:00
f2bf6d682a fix build setup 2021-05-13 14:03:10 +02:00
a1fa8877f7 make core name a cmake option 2021-05-13 09:32:38 +02:00
391f9bb808 remove unneeded constants 2021-05-08 15:14:19 +02:00
ef02dba8c5 add read misa callback 2021-04-09 11:20:51 +02:00
2f4cfb68dc update to latest SCC 2021-04-07 18:56:46 +02:00
7009943106 fix wait for interrupt. Adapt for new SCC structure 2021-04-07 17:42:08 +02:00
0a76ccbdac make RSP register response independend of register definition 2021-03-31 07:48:46 +00:00
32e4aa83b8 use extracted variables 2021-03-27 09:36:52 +00:00
78c7064295 update groovy template to extract used registers 2021-03-26 08:24:45 +00:00
412a4bd9bb update name 2021-03-23 17:13:32 +00:00
ea3ff3c0cd build with SCV lib 2021-03-23 11:57:47 +01:00
b0bcb7febb small fixes for robustness and readability 2021-03-22 22:47:30 +00:00
c941890901 SCC refactoring 2021-03-22 14:50:53 +01:00
51fbc34fb3 change namespace of core complex 2021-03-22 11:57:40 +00:00
4e0f20eba0 rework abort conditions 2021-03-17 19:32:57 +00:00
ff3fa19208 fix RVM description bugs 2021-03-13 10:46:41 +00:00
80057eef32 fix RVC description bugs, remove paged fetch 2021-03-13 10:46:41 +00:00
a5186ff88d optional dependency to TGF_B_src target 2021-03-12 11:16:24 +01:00
f4ec21007b fix signedness issues 2021-03-11 16:12:28 +00:00
ac8eab6e25 update RISC-V desciptions 2021-03-10 17:31:10 +00:00
b7c0fb2b1c fix bitfield structure 2021-03-10 12:40:06 +01:00
768716b064 fix another missing XLEN 2021-03-09 11:07:56 +00:00
bea0dcc387 update missing XLEN 2021-03-09 11:03:37 +00:00
a6691bcd3c update generated code with correct sign extension 2021-03-09 10:21:36 +00:00
40db74ce02 remove tgf_b code generation 2021-03-07 16:26:14 +00:00
c171e3c1ba update CoreDSL descriptions 2021-03-07 10:51:15 +00:00
c251fe15d5 fix desscriptions to conform to ISA spec version 20191213 and TGF-C 2021-03-07 10:51:00 +00:00
dae8acb8a3 checkpoint before refactor 2021-03-06 07:17:42 +00:00
f7cec99fa6 adapt to changes in SCC 2021-03-01 21:08:18 +00:00
be0e7db185 fix templates to comply with CoreDSL2 2021-03-01 21:07:20 +00:00
4aa26b85a0 adapt to change in SCC 2021-03-01 06:36:27 +00:00
9534d58d01 regenerated sources and and add opcode enum to headers
Conflicts:
	gen_input/CoreDSL-Instruction-Set-Description
2021-03-01 06:26:33 +00:00
1668df0531 regenerated sources and and add opcode enum to headers 2021-02-23 08:29:31 +00:00
d8e009c72b update CoreDSL decriptions 2021-02-15 18:15:13 +00:00
d07c8679ed update core definition 2021-02-15 18:14:52 +00:00
3d5b61f301 move boost libraries from tgfs_sc to tgfs library 2021-02-15 18:03:39 +00:00
337f1634c0 add mssing change 2021-02-15 18:01:46 +00:00
72b09472d5 update RISC-V descriptions 2021-02-15 18:01:33 +00:00
3261055871 update description to latest CoreDSL2 2021-02-15 11:35:56 +00:00
34bb8e62ae generate working ISS from CoreDSL 2.0 2021-02-06 14:47:06 +00:00
da7e29fbb7 update definitions of derived constants 2021-01-01 09:19:48 +00:00
c4da47cedd integrate code generation into build process (first attempt) 2020-12-30 07:29:52 +00:00
ab554539e3 first version of tgf_c based on CoreDSL 2.0 2020-12-29 08:48:22 +00:00
d43b35949e fix CMakeList.txt so that it builds without platform and external libs 2020-12-23 16:24:10 +00:00
be49b8b545 Relative path to a submodule 2020-12-10 15:32:03 +01:00
43488676dd Update TGF naming convention 2020-09-11 10:45:44 +02:00
f3d578f050 Remove 64bit support 2020-09-07 14:30:19 +02:00
293c396a0d update core wrapper: remove virtual memory support 2020-09-07 13:29:45 +02:00
6f3963a473 Strip down privileged modes. Only machine mode is supported 2020-09-07 11:54:45 +02:00
969b408288 Implement MHARTID register 2020-09-04 15:37:21 +02:00
886b8f5716 TGF02 is a default core 2020-08-31 14:20:13 +02:00
c2c8fb5ca9 update README 2020-08-24 15:14:49 +02:00
9754e3953f Generate and integrate TGF cores in Ecosystem-VP. Remove obsolete cores 2020-08-24 15:01:54 +02:00
03172e352d move CoreDSL instraction set description files into a dedicated repository CoreDSL-Instruction-Set-Description 2020-08-21 15:57:01 +02:00
8fce0c4759 Generate TGF01 and TGF02 cores 2020-08-20 17:29:36 +02:00
18976e2ce4 adapt to newer gdb protocol 2020-06-22 08:45:12 +02:00
71b976811b add backend selection 2020-06-18 09:58:43 +02:00
edeff7add8 update log macros 2020-06-18 07:38:56 +02:00
e902936931 make interpreter default 2020-06-18 07:22:50 +02:00
55450f4900 [WIP] update dependencies in core desc 2020-06-18 06:18:59 +02:00
c619194465 [WIP] rework generator 2020-06-05 07:25:40 +02:00
abcfb75011 [WIP] 2020-05-31 16:41:04 +02:00
10797a473d modernize build system and cleanup dependencies 2020-05-30 14:16:10 +02:00
0ff6ccf9e2 get all compile clean 2020-05-30 11:27:44 +02:00
97a8ab1680 Merge branch 'feature/interpreter' into develop 2020-05-29 08:54:38 +02:00
72 changed files with 13522 additions and 39136 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "gen_input/CoreDSL-Instruction-Set-Description"]
path = gen_input/CoreDSL-Instruction-Set-Description
url = ../CoreDSL-Instruction-Set-Description.git

View File

@ -1,147 +1,169 @@
cmake_minimum_required(VERSION 3.12)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir
###############################################################################
#
###############################################################################
project(dbt-rise-tgc VERSION 1.0.0)
# CMake useful variables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
include(GNUInstallDirs)
# Set the name of your project here
project("riscv")
find_package(elfio)
include(Common)
if(WITH_LLVM)
if(DEFINED ENV{LLVM_HOME})
find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
endif(DEFINED ENV{LLVM_HOME})
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
endif()
conan_basic_setup()
find_package(Boost COMPONENTS program_options system thread filesystem REQUIRED)
# This sets the include directory for the reference project. This is the -I flag in gcc.
include_directories(
${PROJECT_SOURCE_DIR}/incl
${SOFTFLOAT_INCLUDE_DIRS}
${LLVM_INCLUDE_DIRS}
)
add_dependent_subproject(dbt-core)
include_directories(
${PROJECT_SOURCE_DIR}/incl
${PROJECT_SOURCE_DIR}/../external/elfio
${PROJECT_SOURCE_DIR}/../external/libGIS
${Boost_INCLUDE_DIRS}
)
# Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH)
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
#Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH)
#set(CMAKE_MACOSX_RPATH ON)
#set(CMAKE_SKIP_BUILD_RPATH FALSE)
#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_subdirectory(softfloat)
# library files
FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h)
set(LIB_HEADERS ${RiscVSCHeaders} )
FILE(GLOB TGC_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
)
set(LIB_SOURCES
#src/iss/rv32gc.cpp
src/iss/rv32imac.cpp
#src/iss/rv64i.cpp
#src/iss/rv64gc.cpp
src/iss/mnrv32.cpp
src/vm/llvm/fp_functions.cpp
src/vm/llvm/vm_mnrv32.cpp
#src/vm/llvm/vm_rv32gc.cpp
#src/vm/llvm/vm_rv32imac.cpp
#src/vm/llvm/vm_rv64i.cpp
#src/vm/llvm/vm_rv64gc.cpp
src/vm/tcc/vm_mnrv32.cpp
src/vm/interp/vm_mnrv32.cpp
src/vm/fp_functions.cpp
src/plugin/instruction_count.cpp
src/plugin/cycle_estimate.cpp)
# Define two variables in order not to repeat ourselves.
set(LIBRARY_NAME riscv)
# Define the library
add_library(${LIBRARY_NAME} ${LIB_SOURCES})
SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive)
target_link_libraries(${LIBRARY_NAME} softfloat dbt-core scc-util)
set_target_properties(${LIBRARY_NAME} PROPERTIES
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
src/plugin/cycle_estimate.cpp
${TGC_SOURCES}
)
if(SystemC_FOUND)
set(SC_LIBRARY_NAME riscv_sc)
add_library(${SC_LIBRARY_NAME} src/sysc/core_complex.cpp)
add_definitions(-DWITH_SYSTEMC)
include_directories(${SystemC_INCLUDE_DIRS})
include_directories(${CCI_INCLUDE_DIRS})
if(SCV_FOUND)
add_definitions(-DWITH_SCV)
include_directories(${SCV_INCLUDE_DIRS})
endif()
target_link_libraries(${SC_LIBRARY_NAME} ${LIBRARY_NAME})
target_link_libraries(${SC_LIBRARY_NAME} dbt-core)
target_link_libraries(${SC_LIBRARY_NAME} softfloat)
target_link_libraries(${SC_LIBRARY_NAME} scc)
target_link_libraries(${SC_LIBRARY_NAME} external)
target_link_libraries(${SC_LIBRARY_NAME} ${llvm_libs})
target_link_libraries(${SC_LIBRARY_NAME} ${Boost_LIBRARIES} )
set_target_properties(${SC_LIBRARY_NAME} PROPERTIES
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
)
if(WITH_LLVM)
set(LIB_SOURCES ${LIB_SOURCES}
src/vm/llvm/fp_impl.cpp
#src/vm/llvm/vm_tgf_b.cpp
#src/vm/llvm/vm_tgf_c.cpp
)
endif()
project("riscv-sim")
# Define the library
add_library(${PROJECT_NAME} ${LIB_SOURCES})
# list code gen dependencies
if(TARGET ${CORE_NAME}_cpp)
add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
endif()
# This is a make target, so you can do a "make riscv-sc"
set(APPLICATION_NAME riscv-sim)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC incl)
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-core)
endif()
if(TARGET CONAN_PKG::elfio)
target_link_libraries(${PROJECT_NAME} PUBLIC CONAN_PKG::elfio)
elseif(TARGET elfio::elfio)
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
else()
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
endif()
add_executable(${APPLICATION_NAME} src/main.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
FRAMEWORK FALSE
)
install(TARGETS ${PROJECT_NAME} 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}/${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}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory
FILES_MATCHING # install only matched files
PATTERN "*.h" # select header files
)
###############################################################################
#
###############################################################################
project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp)
# This sets the include directory for the reference project. This is the -I flag in gcc.
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
if(WITH_LLVM)
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
endif()
# Links the target exe against the libraries
target_link_libraries(${APPLICATION_NAME} ${LIBRARY_NAME})
target_link_libraries(${APPLICATION_NAME} jsoncpp)
target_link_libraries(${APPLICATION_NAME} dbt-core)
target_link_libraries(${APPLICATION_NAME} external)
target_link_libraries(${APPLICATION_NAME} ${llvm_libs})
target_link_libraries(${APPLICATION_NAME} ${Boost_LIBRARIES} )
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
if(TARGET Boost::program_options)
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options Boost::thread)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY} ${BOOST_thread_LIBRARY})
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
if (Tcmalloc_FOUND)
target_link_libraries(${APPLICATION_NAME} ${Tcmalloc_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
endif(Tcmalloc_FOUND)
# Says how and where to install software
# Targets:
# * <prefix>/lib/<libraries>
# * header location after install: <prefix>/include/<project>/*.h
# * headers can be included by C++ code `#<project>/Bar.hpp>`
install(TARGETS ${LIBRARY_NAME} ${APPLICATION_NAME}
install(TARGETS tgc-sim
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION lib COMPONENT libs # static lib
RUNTIME DESTINATION bin COMPONENT libs # binaries
LIBRARY DESTINATION lib COMPONENT libs # shared lib
FRAMEWORK DESTINATION bin COMPONENT libs # for mac
PUBLIC_HEADER DESTINATION incl/${PROJECT_NAME} COMPONENT devel # headers for mac (note the different component -> different package)
INCLUDES DESTINATION incl # headers
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}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
)
###############################################################################
#
# SYSTEM PACKAGING (RPM, TGZ, ...)
# _____________________________________________________________________________
###############################################################################
project(dbt-rise-tgc_sc VERSION 1.0.0)
#include(CPackConfig)
include(SystemCPackage)
if(SystemC_FOUND)
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_B)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_C)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_D)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
if(WITH_LLVM)
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
endif()
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/core_complex.h)
set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
)
install(TARGETS ${PROJECT_NAME} 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
)
endif()
#
# CMAKE PACKAGING (for other CMake projects to use this one easily)
# _____________________________________________________________________________
#include(PackageConfigurator)

View File

@ -1,119 +0,0 @@
cmake_minimum_required(VERSION 3.3)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_CURRENT_SOURCE_DIR}/sc-components/cmake)
set(ENABLE_SCV TRUE CACHE BOOL "Enable use of SCV")
set(ENABLE_SHARED TRUE CACHE BOOL "Build shared libraries")
include(GitFunctions)
get_branch_from_git()
# if we are not on master or develop set the submodules to develop
IF(NOT ${GIT_BRANCH} MATCHES "master")
IF(NOT ${GIT_BRANCH} MATCHES "develop")
message(STATUS "main branch is '${GIT_BRANCH}', setting submodules to 'develop'")
set(GIT_BRANCH develop)
endif()
endif()
### set the directory names of the submodules
set(GIT_SUBMODULES elfio libGIS sc-components dbt-core)
set(GIT_SUBMODULE_DIR_sc-components .)
set(GIT_SUBMODULE_DIR_dbt-core .)
### set each submodules's commit or tag that is to be checked out
### (leave empty if you want master)
#set(GIT_SUBMODULE_VERSION_sc-comp 3af6b9836589b082c19d9131c5d0b7afa8ddd7cd)
set(GIT_SUBMODULE_BRANCH_sc-components ${GIT_BRANCH})
set(GIT_SUBMODULE_BRANCH_dbt-core ${GIT_BRANCH})
include(GNUInstallDirs)
include(Submodules)
include(Conan)
#enable_testing()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE)
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
elseif(NOT(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo"))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif()
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(warnings "-Wall -Wextra -Werror")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(warnings "/W4 /WX /EHsc")
endif()
setup_conan()
# This line finds the boost lib and headers.
set(Boost_NO_BOOST_CMAKE ON) # Don't do a find_package in config mode before searching for a regular boost install.
find_package(Boost COMPONENTS program_options system thread filesystem REQUIRED)
if(DEFINED ENV{LLVM_HOME})
find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
endif(DEFINED ENV{LLVM_HOME})
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
find_package(Threads)
find_package(Tcmalloc)
find_package(ZLIB)
find_package(SystemC)
if(SystemC_FOUND)
message(STATUS "SystemC headers at ${SystemC_INCLUDE_DIRS}")
message(STATUS "SystemC library at ${SystemC_LIBRARY_DIRS}")
if(SCV_FOUND)
message(STATUS "SCV headers at ${SCV_INCLUDE_DIRS}")
message(STATUS "SCV library at ${SCV_LIBRARY_DIRS}")
endif(SCV_FOUND)
if(CCI_FOUND)
message(STATUS "CCI headers at ${CCI_INCLUDE_DIRS}")
message(STATUS "CCI library at ${CCI_LIBRARY_DIRS}")
endif()
endif(SystemC_FOUND)
set(PROJECT_3PARTY_DIRS external)
include(clang-format)
set(ENABLE_CLANG_TIDY OFF CACHE BOOL "Add clang-tidy automatically to builds")
if (ENABLE_CLANG_TIDY)
find_program (CLANG_TIDY_EXE NAMES "clang-tidy" PATHS /usr/local/opt/llvm/bin )
if (CLANG_TIDY_EXE)
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
set(CLANG_TIDY_CHECKS "-*,modernize-*")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE};-checks=${CLANG_TIDY_CHECKS};-header-filter='${CMAKE_SOURCE_DIR}/*';-fix"
CACHE STRING "" FORCE)
else()
message(AUTHOR_WARNING "clang-tidy not found!")
set(CMAKE_CXX_CLANG_TIDY "" CACHE STRING "" FORCE) # delete it
endif()
endif()
# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
set(VERSION_MAJOR "1")
set(VERSION_MINOR "0")
set(VERSION_PATCH "0")
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
add_subdirectory(external)
add_subdirectory(dbt-core)
add_subdirectory(sc-components)
add_subdirectory(softfloat)
GET_DIRECTORY_PROPERTY(SOFTFLOAT_INCLUDE_DIRS DIRECTORY softfloat DEFINITION SOFTFLOAT_INCLUDE_DIRS)
add_subdirectory(riscv)
add_subdirectory(platform)
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")

View File

@ -1,18 +1,16 @@
# DBT-RISE-RISCV
Core of an instruction set simulator based on DBT-RISE implementing the RISC-V ISA. The project is hosted at https://git.minres.com/DBT-RISE/DBT-RISE-RISCV .
# DBT-RISE-TGFS
Core of an instruction set simulator based on DBT-RISE implementing Minres The Good Folks Series cores. The project is hosted at https://git.minres.com/DBT-RISE/DBT-RISE-TGFS .
This repo contains only the code of the RISC-V ISS and can only be used with the DBT_RISE. A complete VP using this ISS can be found at https://git.minres.com/VP/RISCV-VP which models SiFives FE310 controlling a brushless DC (BLDC) motor.
This repo contains only the code of the RISC-V ISS and can only be used with the DBT_RISE. A complete VP using this ISS can be found at https://git.minres.com/VP/Ecosystem-VP ~~which models SiFives FE310 controlling a brushless DC (BLDC) motor~~.
This library provide the infrastructure to build RISC-V ISS. Currently part of the library are the following implementations adhering to version 2.2 of the 'The RISC-V Instruction Set Manual Volume I: User-Level ISA':
* RV32IMAC
* RV32GC
* RC64I
* RV64GC
* RV32I (TGF-B)
* RV32MIC (TGF-C)
All pass the respective compliance tests. Along with those ISA implementations there is a wrapper implementing the M/S/U modes inlcuding virtual memory management and CSRs as of privileged spec 1.10. The main.cpp in src allows to build a standalone ISS when integrated into a top-level project. For further information please have a look at [https://git.minres.com/VP/RISCV-VP](https://git.minres.com/VP/RISCV-VP).
All pass the respective compliance tests. Along with those ISA implementations there is a wrapper (riscv_hart_m_p.h) implementing the Machine privileged mode as of privileged spec 1.10. The main.cpp in src allows to build a stand-alone ISS when integrated into a top-level project. For further information please have a look at [https://git.minres.com/VP/RISCV-VP](https://git.minres.com/VP/RISCV-VP).
Last but not least an SystemC wrapper is provided which allows easy integration into SystemC based virtual platforms.
Since DBT-RISE uses a generative approch other needed combinations or custom extension can be generated. For further information please contact [info@minres.com](mailto:info@minres.com).
Since DBT-RISE uses a generative approach other needed combinations or custom extension can be generated. For further information please contact [info@minres.com](mailto:info@minres.com).

30
contrib/build.tcl Normal file
View File

@ -0,0 +1,30 @@
namespace eval Specification {
proc buildproc { args } {
global env
variable installDir
variable compiler
variable compiler [::scsh::get_backend_compiler]
# set target $machine
set target [::scsh::machine]
set linkerOptions ""
set preprocessorOptions ""
set libversion $compiler
switch -exact -- $target {
"linux" {
set install_dir $::env(TGFS_INSTALL_ROOT)
set incldir "${install_dir}/include"
set libdir "${install_dir}/lib64"
set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"]
# Set the Linker paths.
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc"]
}
default {
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"
return
}
}
::scsh::cwr_append_ipsimbld_opts preprocessor "$preprocessorOptions"
::scsh::cwr_append_ipsimbld_opts linker "$linkerOptions"
}
::scsh::add_build_callback [namespace current]::buildproc
}

4
contrib/tgc_import.cc Normal file
View File

@ -0,0 +1,4 @@
#include "sysc/core_complex.h"
void modules() { sysc::tgfs::core_complex i_core_complex("core_complex"); }

50
contrib/tgc_import.tcl Normal file
View File

@ -0,0 +1,50 @@
#############################################################################
#
#############################################################################
proc getScriptDirectory {} {
set dispScriptFile [file normalize [info script]]
set scriptFolder [file dirname $dispScriptFile]
return $scriptFolder
}
if { $::env(SNPS_VP_PRODUCT) == "PAULTRA" } {
set hardware /HARDWARE/HW/HW
} else {
set hardware /HARDWARE
}
set scriptDir [getScriptDirectory]
set top_design_name core_complex
set clocks clk_i
set resets rst_i
set model_prefix "i_"
set model_postfix ""
::pct::new_project
::pct::open_library TLM2_PL
::pct::clear_systemc_defines
::pct::clear_systemc_include_path
::pct::add_to_systemc_include_path $::env(TGFS_INSTALL_ROOT)/include
::pct::set_import_protocol_generation_flag false
::pct::set_update_existing_encaps_flag true
::pct::set_dynamic_port_arrays_flag true
::pct::set_import_scml_properties_flag true
::pct::load_modules --set-category modules tgc_import.cc
# Set Port Protocols correctly
set block ${top_design_name}
foreach clock ${clocks} {
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${clock} SYSTEM_LIBRARY:CLOCK
}
foreach reset ${resets} {
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET
}
::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16
# Set compile settings and look
set block SYSTEM_LIBRARY:${top_design_name}
::pct::set_encap_build_script $block/${top_design_name} $scriptDir/build.tcl
::pct::set_background_color_rgb $block 255 255 255 255
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${top_design_name}
# export the result as component
::pct::export_system_library ${top_design_name} ${top_design_name}.xml

View File

@ -1,50 +0,0 @@
InsructionSet RISCVBase {
constants {
XLEN,
fence:=0,
fencei:=1,
fencevmal:=2,
fencevmau:=3
}
address_spaces {
MEM[8], CSR[XLEN], FENCE[XLEN], RES[8]
}
registers {
[31:0] X[XLEN],
PC[XLEN](is_pc),
alias ZERO[XLEN] is X[0],
alias RA[XLEN] is X[1],
alias SP[XLEN] is X[2],
alias GP[XLEN] is X[3],
alias TP[XLEN] is X[4],
alias T0[XLEN] is X[5],
alias T1[XLEN] is X[6],
alias T2[XLEN] is X[7],
alias S0[XLEN] is X[8],
alias S1[XLEN] is X[9],
alias A0[XLEN] is X[10],
alias A1[XLEN] is X[11],
alias A2[XLEN] is X[12],
alias A3[XLEN] is X[13],
alias A4[XLEN] is X[14],
alias A5[XLEN] is X[15],
alias A6[XLEN] is X[16],
alias A7[XLEN] is X[17],
alias S2[XLEN] is X[18],
alias S3[XLEN] is X[19],
alias S4[XLEN] is X[20],
alias S5[XLEN] is X[21],
alias S6[XLEN] is X[22],
alias S7[XLEN] is X[23],
alias S8[XLEN] is X[24],
alias S9[XLEN] is X[25],
alias S10[XLEN] is X[26],
alias S11[XLEN] is X[27],
alias T3[XLEN] is X[28],
alias T4[XLEN] is X[29],
alias T5[XLEN] is X[30],
alias T6[XLEN] is X[31]
}
}

View File

@ -1,309 +0,0 @@
import "RISCVBase.core_desc"
InsructionSet RV32I extends RISCVBase{
instructions {
LUI{
encoding: imm[31:12]s | rd[4:0] | b0110111;
args_disass: "{name(rd)}, {imm:#05x}";
if(rd!=0) X[rd] <= imm;
}
AUIPC{
encoding: imm[31:12]s | rd[4:0] | b0010111;
args_disass: "{name(rd)}, {imm:#08x}";
if(rd!=0) X[rd] <= PC's+imm;
}
JAL(no_cont){
encoding: imm[20:20]s | imm[10:1]s | imm[11:11]s | imm[19:12]s | rd[4:0] | b1101111;
args_disass: "{name(rd)}, {imm:#0x}";
if(rd!=0) X[rd] <= PC+4;
PC<=PC's+imm;
}
JALR(no_cont){
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111;
args_disass: "{name(rd)}, {name(rs1)}, {imm:#0x}";
val new_pc[XLEN] <= X[rs1]'s+ imm;
val align[XLEN] <= new_pc & 0x2;
if(align != 0){
raise(0, 0);
} else {
if(rd!=0) X[rd] <= PC+4;
PC<=new_pc & ~0x1;
}
}
BEQ(no_cont,cond){
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]==X[rs2], PC's+imm, PC+4);
}
BNE(no_cont,cond){
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b001 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]!=X[rs2], PC's+imm, PC+4);
}
BLT(no_cont,cond){
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b100 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]s<X[rs2]s, PC's+imm, PC+4);
}
BGE(no_cont,cond) {
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b101 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]s>=X[rs2]s, PC's+imm, PC+4);
}
BLTU(no_cont,cond) {
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b110 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]<X[rs2],PC's+imm, PC+4);
}
BGEU(no_cont,cond) {
encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b111 | imm[4:1]s | imm[11:11]s | b1100011;
args_disass:"{name(rs1)}, {name(rs2)}, {imm:#0x}";
PC<=choose(X[rs1]>=X[rs2], PC's+imm, PC+4);
}
LB {
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=sext(MEM[offs]);
}
LH {
encoding: imm[11:0]s | rs1[4:0] | b001 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=sext(MEM[offs]{16});
}
LW {
encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=sext(MEM[offs]{32});
}
LBU {
encoding: imm[11:0]s | rs1[4:0] | b100 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=zext(MEM[offs]);
}
LHU {
encoding: imm[11:0]s | rs1[4:0] | b101 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=zext(MEM[offs]{16});
}
SB {
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:0]s | b0100011;
args_disass:"{name(rs2)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs] <= X[rs2];
}
SH {
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b001 | imm[4:0]s | b0100011;
args_disass:"{name(rs2)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs]{16} <= X[rs2];
}
SW {
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b010 | imm[4:0]s | b0100011;
args_disass:"{name(rs2)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs]{32} <= X[rs2];
}
ADDI {
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if(rd != 0) X[rd] <= X[rs1]'s + imm;
}
SLTI {
encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if (rd != 0) X[rd] <= choose(X[rs1]s < imm's, 1, 0);
}
SLTIU {
encoding: imm[11:0]s | rs1[4:0] | b011 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
val full_imm[XLEN] <= imm's;
if (rd != 0) X[rd] <= choose(X[rs1]'u < full_imm'u, 1, 0);
}
XORI {
encoding: imm[11:0]s | rs1[4:0] | b100 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if(rd != 0) X[rd] <= X[rs1]s ^ imm;
}
ORI {
encoding: imm[11:0]s | rs1[4:0] | b110 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if(rd != 0) X[rd] <= X[rs1]s | imm;
}
ANDI {
encoding: imm[11:0]s | rs1[4:0] | b111 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if(rd != 0) X[rd] <= X[rs1]s & imm;
}
SLLI {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(shamt > 31){
raise(0,0);
} else {
if(rd != 0) X[rd] <= shll(X[rs1], shamt);
}
}
SRLI {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(shamt > 31){
raise(0,0);
} else {
if(rd != 0) X[rd] <= shrl(X[rs1], shamt);
}
}
SRAI {
encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(shamt > 31){
raise(0,0);
} else {
if(rd != 0) X[rd] <= shra(X[rs1], shamt);
}
}
ADD {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= X[rs1] + X[rs2];
}
SUB {
encoding: b0100000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= X[rs1] - X[rs2];
}
SLL {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= shll(X[rs1], X[rs2]&(XLEN-1));
}
SLT {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if (rd != 0) X[rd] <= choose(X[rs1]s < X[rs2]s, 1, 0);
}
SLTU {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if (rd != 0) X[rd] <= choose(zext(X[rs1]) < zext(X[rs2]), 1, 0);
}
XOR {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= X[rs1] ^ X[rs2];
}
SRL {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= shrl(X[rs1], X[rs2]&(XLEN-1));
}
SRA {
encoding: b0100000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= shra(X[rs1], X[rs2]&(XLEN-1));
}
OR {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= X[rs1] | X[rs2];
}
AND {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0) X[rd] <= X[rs1] & X[rs2];
}
FENCE {
encoding: b0000 | pred[3:0] | succ[3:0] | rs1[4:0] | b000 | rd[4:0] | b0001111;
FENCE[fence] <= pred<<4 | succ;
}
FENCE_I(flush) {
encoding: imm[11:0] | rs1[4:0] | b001 | rd[4:0] | b0001111 ;
FENCE[fencei] <= imm;
}
ECALL(no_cont) {
encoding: b000000000000 | b00000 | b000 | b00000 | b1110011;
raise(0, 11);
}
EBREAK(no_cont) {
encoding: b000000000001 | b00000 | b000 | b00000 | b1110011;
raise(0, 3);
}
URET(no_cont) {
encoding: b0000000 | b00010 | b00000 | b000 | b00000 | b1110011;
leave(0);
}
SRET(no_cont) {
encoding: b0001000 | b00010 | b00000 | b000 | b00000 | b1110011;
leave(1);
}
MRET(no_cont) {
encoding: b0011000 | b00010 | b00000 | b000 | b00000 | b1110011;
leave(3);
}
WFI {
encoding: b0001000 | b00101 | b00000 | b000 | b00000 | b1110011;
wait(1);
}
SFENCE.VMA {
encoding: b0001001 | rs2[4:0] | rs1[4:0] | b000 | b00000 | b1110011;
FENCE[fencevmal] <= rs1;
FENCE[fencevmau] <= rs2;
}
CSRRW {
encoding: csr[11:0] | rs1[4:0] | b001 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {name(rs1)}";
val rs_val[XLEN] <= X[rs1];
if(rd!=0){
val csr_val[XLEN] <= CSR[csr];
CSR[csr] <= rs_val;
// make sure Xrd is updated once CSR write succeeds
X[rd] <= csr_val;
} else {
CSR[csr] <= rs_val;
}
}
CSRRS {
encoding: csr[11:0] | rs1[4:0] | b010 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {name(rs1)}";
val xrd[XLEN] <= CSR[csr];
val xrs1[XLEN] <= X[rs1];
if(rd!=0) X[rd] <= xrd;
if(rs1!=0) CSR[csr] <= xrd | xrs1;
}
CSRRC {
encoding: csr[11:0] | rs1[4:0] | b011 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {name(rs1)}";
val xrd[XLEN] <= CSR[csr];
val xrs1[XLEN] <= X[rs1];
if(rd!=0) X[rd] <= xrd;
if(rs1!=0) CSR[csr] <= xrd & ~xrs1;
}
CSRRWI {
encoding: csr[11:0] | zimm[4:0] | b101 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {zimm:#0x}";
if(rd!=0) X[rd] <= CSR[csr];
CSR[csr] <= zext(zimm);
}
CSRRSI {
encoding: csr[11:0] | zimm[4:0] | b110 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {zimm:#0x}";
val res[XLEN] <= CSR[csr];
if(zimm!=0) CSR[csr] <= res | zext(zimm);
// make sure rd is written after csr write succeeds
if(rd!=0) X[rd] <= res;
}
CSRRCI {
encoding: csr[11:0] | zimm[4:0] | b111 | rd[4:0] | b1110011;
args_disass:"{name(rd)}, {csr}, {zimm:#0x}";
val res[XLEN] <= CSR[csr];
if(rd!=0) X[rd] <= res;
if(zimm!=0) CSR[csr] <= res & ~zext(zimm, XLEN);
}
}
}

View File

@ -1,116 +0,0 @@
import "RV32I.core_desc"
InsructionSet RV64I extends RV32I {
instructions{
LWU { // 80000104: 0000ef03 lwu t5,0(ra)
encoding: imm[11:0]s | rs1[4:0] | b110 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s+imm;
if(rd!=0) X[rd]<=zext(MEM[offs]{32});
}
LD{
encoding: imm[11:0]s | rs1[4:0] | b011 | rd[4:0] | b0000011;
args_disass:"{name(rd)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
if(rd!=0) X[rd]<=sext(MEM[offs]{64});
}
SD{
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b011 | imm[4:0]s | b0100011;
args_disass:"{name(rs2)}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs]{64} <= X[rs2];
}
SLLI {
encoding: b000000 | shamt[5:0] | rs1[4:0] | b001 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0) X[rd] <= shll(X[rs1], shamt);
}
SRLI {
encoding: b000000 | shamt[5:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0) X[rd] <= shrl(X[rs1], shamt);
}
SRAI {
encoding: b010000 | shamt[5:0] | rs1[4:0] | b101 | rd[4:0] | b0010011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0) X[rd] <= shra(X[rs1], shamt);
}
ADDIW {
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0011011;
args_disass:"{name(rd)}, {name(rs1)}, {imm}";
if(rd != 0){
val res[32] <= X[rs1]{32}'s + imm;
X[rd] <= sext(res);
}
}
SLLIW {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0011011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0){
val sh_val[32] <= shll(X[rs1]{32}, shamt);
X[rd] <= sext(sh_val);
}
}
SRLIW {
encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0011011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0){
val sh_val[32] <= shrl(X[rs1]{32}, shamt);
X[rd] <= sext(sh_val);
}
}
SRAIW {
encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0011011;
args_disass:"{name(rd)}, {name(rs1)}, {shamt}";
if(rd != 0){
val sh_val[32] <= shra(X[rs1]{32}, shamt);
X[rd] <= sext(sh_val);
}
}
ADDW {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011;
if(rd != 0){
val res[32] <= X[rs1]{32} + X[rs2]{32};
X[rd] <= sext(res);
}
}
SUBW {
encoding: b0100000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011;
if(rd != 0){
val res[32] <= X[rs1]{32} - X[rs2]{32};
X[rd] <= sext(res);
}
}
SLLW {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val mask[32] <= 0x1f;
val count[32] <= X[rs2]{32} & mask;
val sh_val[32] <= shll(X[rs1]{32}, count);
X[rd] <= sext(sh_val);
}
}
SRLW {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val mask[32] <= 0x1f;
val count[32] <= X[rs2]{32} & mask;
val sh_val[32] <= shrl(X[rs1]{32}, count);
X[rd] <= sext(sh_val);
}
}
SRAW {
encoding: b0100000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val mask[32] <= 0x1f;
val count[32] <= X[rs2]{32} & mask;
val sh_val[32] <= shra(X[rs1]{32}, count);
X[rd] <= sext(sh_val);
}
}
}
}

View File

@ -1,210 +0,0 @@
import "RISCVBase.core_desc"
InsructionSet RV32A extends RISCVBase{
instructions{
LR.W {
encoding: b00010 | aq[0:0] | rl[0:0] | b00000 | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}";
if(rd!=0){
val offs[XLEN] <= X[rs1];
X[rd]<= sext(MEM[offs]{32}, XLEN);
RES[offs]{32}<=sext(-1, 32);
}
}
SC.W {
encoding: b00011 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)}";
val offs[XLEN] <= X[rs1];
val res1[32] <= RES[offs]{32};
if(res1!=0)
MEM[offs]{32} <= X[rs2];
if(rd!=0) X[rd]<= choose(res1!=zext(0, 32), 0, 1);
}
AMOSWAP.W{
encoding: b00001 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
if(rd!=0) X[rd]<=sext(MEM[offs]{32});
MEM[offs]{32}<=X[rs2];
}
AMOADD.W{
encoding: b00000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN]<=res1 + X[rs2];
MEM[offs]{32}<=res2;
}
AMOXOR.W{
encoding: b00100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN]<=res1 ^ X[rs2];
MEM[offs]{32}<=res2;
}
AMOAND.W{
encoding: b01100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN] <=res1 & X[rs2];
MEM[offs]{32}<=res2;
}
AMOOR.W {
encoding: b01000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN]<=res1 | X[rs2];
MEM[offs]{32}<=res2;
}
AMOMIN.W{
encoding: b10000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd] <= res1;
val res2[XLEN] <= choose(res1's > X[rs2]s, X[rs2], res1);
MEM[offs]{32} <= res2;
}
AMOMAX.W{
encoding: b10100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN]<= choose(res1's<X[rs2]s, X[rs2], res1);
MEM[offs]{32}<=res2;
}
AMOMINU.W{
encoding: b11000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd]<=res1;
val res2[XLEN]<= choose(res1>X[rs2], X[rs2], res1);
MEM[offs]{32}<=res2;
}
AMOMAXU.W{
encoding: b11100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN]<=X[rs1];
val res1[XLEN] <= sext(MEM[offs]{32});
if(rd!=0) X[rd] <= res1;
val res2[XLEN] <= choose(res1 < X[rs2], X[rs2], res1);
MEM[offs]{32} <= res2;
}
}
}
InsructionSet RV64A extends RV32A {
instructions{
LR.D {
encoding: b00010 | aq[0:0] | rl[0:0] | b00000 | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}";
if(rd!=0){
val offs[XLEN] <= X[rs1];
X[rd]<= sext(MEM[offs]{64}, XLEN);
RES[offs]{64}<=sext(-1, 64);
}
}
SC.D {
encoding: b00011 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)}";
val offs[XLEN] <= X[rs1];
val res[64] <= RES[offs];
if(res!=0){
MEM[offs]{64} <= X[rs2];
if(rd!=0) X[rd]<=0;
} else{
if(rd!=0) X[rd]<= 1;
}
}
AMOSWAP.D{
encoding: b00001 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
if(rd!=0) X[rd] <= sext(MEM[offs]{64});
MEM[offs]{64} <= X[rs2];
}
AMOADD.D{
encoding: b00000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd]<=res;
val res2[XLEN] <= res + X[rs2];
MEM[offs]{64}<=res2;
}
AMOXOR.D{
encoding: b00100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res;
val res2[XLEN] <= res ^ X[rs2];
MEM[offs]{64} <= res2;
}
AMOAND.D{
encoding: b01100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res;
val res2[XLEN] <= res & X[rs2];
MEM[offs]{64} <= res2;
}
AMOOR.D {
encoding: b01000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res;
val res2[XLEN] <= res | X[rs2];
MEM[offs]{64} <= res2;
}
AMOMIN.D{
encoding: b10000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res1[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res1;
val res2[XLEN] <= choose(res1's > X[rs2]s, X[rs2], res1);
MEM[offs]{64} <= res2;
}
AMOMAX.D{
encoding: b10100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res;
val res2[XLEN] <= choose(res s < X[rs2]s, X[rs2], res);
MEM[offs]{64} <= res2;
}
AMOMINU.D{
encoding: b11000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res;
val res2[XLEN] <= choose(res > X[rs2], X[rs2], res);
MEM[offs]{64} <= res2;
}
AMOMAXU.D{
encoding: b11100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
args_disass: "{name(rd)}, {name(rs1)}, {name(rs2)} (aqu={aq},rel={rl})";
val offs[XLEN] <= X[rs1];
val res1[XLEN] <= sext(MEM[offs]{64});
if(rd!=0) X[rd] <= res1;
val res2[XLEN] <= choose(res1 < X[rs2], X[rs2], res1);
MEM[offs]{64} <= res2;
}
}
}

View File

@ -1,367 +0,0 @@
import "RISCVBase.core_desc"
InsructionSet RV32IC extends RISCVBase{
instructions{
JALR(no_cont){ // overwriting the implementation if rv32i, alignment does not need to be word
encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111;
args_disass: "{name(rd)}, {name(rs1)}, {imm:#0x}";
val new_pc[XLEN] <= X[rs1]s + imm;
if(rd!=0) X[rd] <= PC+4;
PC<=new_pc & ~0x1;
}
C.ADDI4SPN { //(RES, imm=0)
encoding: b000 | imm[5:4] | imm[9:6] | imm[2:2] | imm[3:3] | rd[2:0] | b00;
args_disass: "{name(rd)}, {imm:#05x}";
if(imm == 0) raise(0, 2);
X[rd+8] <= X[2] + imm;
}
C.LW { // (RV32)
encoding: b010 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rd[2:0] | b00;
args_disass: "{name(8+rd)}, {uimm:#05x}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
X[rd+8] <= sext(MEM[offs]{32});
}
C.SW {//(RV32)
encoding: b110 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rs2[2:0] | b00;
args_disass: "{name(8+rs2)}, {uimm:#05x}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
MEM[offs]{32} <= X[rs2+8];
}
C.ADDI {//(RV32)
encoding:b000 | imm[5:5]s | rs1[4:0] | imm[4:0]s | b01;
args_disass: "{name(rs1)}, {imm:#05x}";
X[rs1] <= X[rs1]'s + imm;
}
C.NOP {
encoding:b000 | b0 | b00000 | b00000 | b01;
}
// C.JAL will be overwritten by C.ADDIW for RV64/128
C.JAL(no_cont) {//(RV32)
encoding: b001 | imm[11:11]s | imm[4:4]s | imm[9:8]s | imm[10:10]s | imm[6:6]s | imm[7:7]s | imm[3:1]s | imm[5:5]s | b01;
args_disass: "{imm:#05x}";
X[1] <= PC+2;
PC<=PC's+imm;
}
C.LI {//(RV32)
encoding:b010 | imm[5:5]s | rd[4:0] | imm[4:0]s | b01;
args_disass: "{name(rd)}, {imm:#05x}";
if(rd == 0) raise(0, 2); //TODO: should it be handled as trap?
X[rd] <= imm;
}
// order matters here as C.ADDI16SP overwrites C.LUI vor rd==2
C.LUI {//(RV32)
encoding:b011 | imm[17:17] | rd[4:0] | imm[16:12]s | b01;
args_disass: "{name(rd)}, {imm:#05x}";
if(rd == 0) raise(0, 2); //TODO: should it be handled as trap?
if(imm == 0) raise(0, 2); //TODO: should it be handled as trap?
X[rd] <= imm;
}
C.ADDI16SP {//(RV32)
encoding:b011 | imm[9:9]s | b00010 | imm[4:4]s | imm[6:6]s | imm[8:7]s | imm[5:5]s | b01;
args_disass: "{imm:#05x}";
X[2] <= X[2]s + imm;
}
C.SRLI {//(RV32 nse)
encoding:b100 | b0 | b00 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shrl(X[rs1_idx], shamt);
}
C.SRAI {//(RV32)
encoding:b100 | b0 | b01 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shra(X[rs1_idx], shamt);
}
C.ANDI {//(RV32)
encoding:b100 | imm[5:5]s | b10 | rs1[2:0] | imm[4:0]s | b01;
args_disass: "{name(8+rs1)}, {imm:#05x}";
val rs1_idx[5] <= rs1 + 8;
X[rs1_idx] <= X[rs1_idx]s & imm;
}
C.SUB {//(RV32)
encoding:b100 | b0 | b11 | rd[2:0] | b00 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rs2)}";
val rd_idx[5] <= rd + 8;
X[rd_idx] <= X[rd_idx] - X[rs2 + 8];
}
C.XOR {//(RV32)
encoding:b100 | b0 | b11 | rd[2:0] | b01 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rs2)}";
val rd_idx[5] <= rd + 8;
X[rd_idx] <= X[rd_idx] ^ X[rs2 + 8];
}
C.OR {//(RV32)
encoding:b100 | b0 | b11 | rd[2:0] | b10 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rs2)}";
val rd_idx[5] <= rd + 8;
X[rd_idx] <= X[rd_idx] | X[rs2 + 8];
}
C.AND {//(RV32)
encoding:b100 | b0 | b11 | rd[2:0] | b11 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rs2)}";
val rd_idx[5] <= rd + 8;
X[rd_idx] <= X[rd_idx] & X[rs2 + 8];
}
C.J(no_cont) {//(RV32)
encoding:b101 | imm[11:11]s | imm[4:4]s | imm[9:8]s | imm[10:10]s | imm[6:6]s | imm[7:7]s | imm[3:1]s | imm[5:5]s | b01;
args_disass: "{imm:#05x}";
PC<=PC's+imm;
}
C.BEQZ(no_cont,cond) {//(RV32)
encoding:b110 | imm[8:8]s | imm[4:3]s | rs1[2:0] | imm[7:6]s |imm[2:1]s | imm[5:5]s | b01;
args_disass: "{name(8+rs1)}, {imm:#05x}";
PC<=choose(X[rs1+8]==0, PC's+imm, PC+2);
}
C.BNEZ(no_cont,cond) {//(RV32)
encoding:b111 | imm[8:8]s | imm[4:3]s | rs1[2:0] | imm[7:6]s | imm[2:1]s | imm[5:5]s | b01;
args_disass: "{name(8+rs1)}, {imm:#05x}";
PC<=choose(X[rs1+8]!=0, PC's+imm, PC+2);
}
C.SLLI {//(RV32)
encoding:b000 | b0 | rs1[4:0] | shamt[4:0] | b10;
args_disass: "{name(rs1)}, {shamt}";
if(rs1 == 0) raise(0, 2);
X[rs1] <= shll(X[rs1], shamt);
}
C.LWSP {//
encoding:b010 | uimm[5:5] | rd[4:0] | uimm[4:2] | uimm[7:6] | b10;
args_disass: "{name(rd)}, sp, {uimm:#05x}";
val offs[XLEN] <= X[2] + uimm;
X[rd] <= sext(MEM[offs]{32});
}
// order matters as C.JR is a special case of C.MV
C.MV {//(RV32)
encoding:b100 | b0 | rd[4:0] | rs2[4:0] | b10;
args_disass: "{name(rd)}, {name(rs2)}";
X[rd] <= X[rs2];
}
C.JR(no_cont) {//(RV32)
encoding:b100 | b0 | rs1[4:0] | b00000 | b10;
args_disass: "{name(rs1)}";
PC <= X[rs1];
}
// order matters as C.EBREAK is a special case of C.JALR which is a special case of C.ADD
C.ADD {//(RV32)
encoding:b100 | b1 | rd[4:0] | rs2[4:0] | b10;
args_disass: "{name(rd)}, {name(rs2)}";
X[rd] <= X[rd] + X[rs2];
}
C.JALR(no_cont) {//(RV32)
encoding:b100 | b1 | rs1[4:0] | b00000 | b10;
args_disass: "{name(rs1)}";
X[1] <= PC+2;
PC<=X[rs1];
}
C.EBREAK(no_cont) {//(RV32)
encoding:b100 | b1 | b00000 | b00000 | b10;
raise(0, 3);
}
C.SWSP {//
encoding:b110 | uimm[5:2] | uimm[7:6] | rs2[4:0] | b10;
args_disass: "{name(rs2)}, {uimm:#05x}(sp)";
val offs[XLEN] <= X[2] + uimm;
MEM[offs]{32} <= X[rs2];
}
DII(no_cont) { // Defined Illegal Instruction
encoding:b000 | b0 | b00000 | b00000 | b00;
raise(0, 2);
}
}
}
InsructionSet RV32FC extends RV32IC{
constants {
FLEN
}
registers {
[31:0] F[FLEN]
}
instructions{
C.FLW {
encoding: b011 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rd[2:0] | b00;
args_disass:"f(8+{rd}), {uimm}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
val res[32] <= MEM[offs]{32};
if(FLEN==32)
F[rd+8] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd+8] <= (upper<<32) | zext(res, FLEN);
}
}
C.FSW {
encoding: b111 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rs2[2:0] | b00;
args_disass:"f(8+{rs2}), {uimm}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
MEM[offs]{32}<=F[rs2+8]{32};
}
C.FLWSP {
encoding:b011 | uimm[5:5] | rd[4:0] | uimm[4:2] | uimm[7:6] | b10;
args_disass:"f{rd}, {uimm}(x2)";
val offs[XLEN] <= X[2]+uimm;
val res[32] <= MEM[offs]{32};
if(FLEN==32)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
C.FSWSP {
encoding:b111 | uimm[5:2] | uimm[7:6] | rs2[4:0] | b10;
args_disass:"f{rs2}, {uimm}(x2), ";
val offs[XLEN] <= X[2]+uimm;
MEM[offs]{32}<=F[rs2]{32};
}
}
}
InsructionSet RV32DC extends RV32IC{
constants {
FLEN
}
registers {
[31:0] F[FLEN]
}
instructions{
C.FLD { //(RV32/64)
encoding: b001 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00;
args_disass:"f(8+{rd}), {uimm}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
val res[64] <= MEM[offs]{64};
if(FLEN==64)
F[rd+8] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd+8] <= (upper<<64) | res;
}
}
C.FSD { //(RV32/64)
encoding: b101 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00;
args_disass:"f(8+{rs2}), {uimm}({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8]+uimm;
MEM[offs]{64}<=F[rs2+8]{64};
}
C.FLDSP {//(RV32/64)
encoding:b001 | uimm[5:5] | rd[4:0] | uimm[4:3] | uimm[8:6] | b10;
args_disass:"f{rd}, {uimm}(x2)";
val offs[XLEN] <= X[2]+uimm;
val res[64] <= MEM[offs]{64};
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | zext(res, FLEN);
}
}
C.FSDSP {//(RV32/64)
encoding:b101 | uimm[5:3] | uimm[8:6] | rs2[4:0] | b10;
args_disass:"f{rs2}, {uimm}(x2), ";
val offs[XLEN] <= X[2]+uimm;
MEM[offs]{64}<=F[rs2]{64};
}
}
}
InsructionSet RV64IC extends RV32IC {
instructions{
C.LD {//(RV64/128)
encoding:b011 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00;
args_disass: "{name(8+rd)}, {uimm},({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8] + uimm;
X[rd+8]<=sext(MEM[offs]{64});
}
C.SD { //(RV64/128)
encoding:b111 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00;
args_disass: "{name(8+rs2)}, {uimm},({name(8+rs1)})";
val offs[XLEN] <= X[rs1+8] + uimm;
MEM[offs]{64} <= X[rs2+8];
}
C.SUBW {//(RV64/128, RV32 res)
encoding:b100 | b1 | b11 | rd[2:0] | b00 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rd)}, {name(8+rs2)}";
val res[32] <= X[rd+8]{32} - X[rs2+8]{32};
X[rd+8] <= sext(res);
}
C.ADDW {//(RV64/128 RV32 res)
encoding:b100 | b1 | b11 | rd[2:0] | b01 | rs2[2:0] | b01;
args_disass: "{name(8+rd)}, {name(8+rd)}, {name(8+rs2)}";
val res[32] <= X[rd+8]{32} + X[rs2+8]{32};
X[rd+8] <= sext(res);
}
C.ADDIW {//(RV64/128)
encoding:b001 | imm[5:5]s | rs1[4:0] | imm[4:0]s | b01;
args_disass: "{name(rs1)}, {imm:#05x}";
if(rs1 != 0){
val res[32] <= X[rs1]{32}'s + imm;
X[rs1] <= sext(res);
}
}
C.SRLI {//(RV64)
encoding:b100 | shamt[5:5] | b00 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shrl(X[rs1_idx], shamt);
}
C.SRAI {//(RV64)
encoding:b100 | shamt[5:5] | b01 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shra(X[rs1_idx], shamt);
}
C.SLLI {//(RV64)
encoding:b000 | shamt[5:5] | rs1[4:0] | shamt[4:0] | b10;
args_disass: "{name(rs1)}, {shamt}";
if(rs1 == 0) raise(0, 2);
X[rs1] <= shll(X[rs1], shamt);
}
C.LDSP {//(RV64/128
encoding:b011 | uimm[5:5] | rd[4:0] | uimm[4:3] | uimm[8:6] | b10;
args_disass:"{name(rd)}, {uimm}(sp)";
val offs[XLEN] <= X[2] + uimm;
if(rd!=0) X[rd]<=sext(MEM[offs]{64});
}
C.SDSP {//(RV64/128)
encoding:b111 | uimm[5:3] | uimm[8:6] | rs2[4:0] | b10;
args_disass:"{name(rs2)}, {uimm}(sp)";
val offs[XLEN] <= X[2] + uimm;
MEM[offs]{64} <= X[rs2];
}
}
}
InsructionSet RV128IC extends RV64IC {
instructions{
C.SRLI {//(RV128)
encoding:b100 | shamt[5:5] | b00 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shrl(X[rs1_idx], shamt);
}
C.SRAI {//(RV128)
encoding:b100 | shamt[5:5] | b01 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shra(X[rs1_idx], shamt);
}
C.SLLI {//(RV128)
encoding:b000 | shamt[5:5] | rs1[4:0] | shamt[4:0] | b10;
args_disass: "{name(rs1)}, {shamt}";
if(rs1 == 0) raise(0, 2);
X[rs1] <= shll(X[rs1], shamt);
}
C.LQ { //(RV128)
encoding:b001 | uimm[5:4] | uimm[8:8] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00;
}
C.SQ { //(RV128)
encoding:b101 | uimm[5:4] | uimm[8:8] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00;
}
C.SQSP {//(RV128)
encoding:b101 | uimm[5:4] | uimm[9:6] | rs2[4:0] | b10;
}
}
}

View File

@ -1,360 +0,0 @@
import "RISCVBase.core_desc"
InsructionSet RV32D extends RISCVBase{
constants {
FLEN, FFLAG_MASK := 0x1f
}
registers {
[31:0] F[FLEN], FCSR[32]
}
instructions{
FLD {
encoding: imm[11:0]s | rs1[4:0] | b011 | rd[4:0] | b0000111;
args_disass:"f{rd}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
val res[64] <= MEM[offs]{64};
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FSD {
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b011 | imm[4:0]s | b0100111;
args_disass:"f{rs2}, {imm}({name(rs1)})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs]{64}<=F[rs2]{64};
}
FMADD.D {
encoding: rs3[4:0] | b01 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<= F[rs1]f * F[rs2]f + F[rs3]f;
val res[64] <= fdispatch_fmadd_d(F[rs1]{64}, F[rs2]{64}, F[rs3]{64}, zext(0, 64), choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMSUB.D {
encoding: rs3[4:0] | b01 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000111;
args_disass:"{name(rd)}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=F[rs1]f * F[rs2]f - F[rs3]f;
val res[64] <= fdispatch_fmadd_d(F[rs1]{64}, F[rs2]{64}, F[rs3]{64}, zext(1, 32), choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FNMADD.D {
encoding: rs3[4:0] | b01 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001111;
args_disass:"{name(rd)}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=-F[rs1]f * F[rs2]f + F[rs3]f;
val res[64] <= fdispatch_fmadd_d(F[rs1]{64}, F[rs2]{64}, F[rs3]{64}, zext(2, 32), choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FNMSUB.D {
encoding: rs3[4:0] | b01 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=-F[rs1]f * F[rs2]f - F[rs3]f;
val res[64] <= fdispatch_fmadd_d(F[rs1]{64}, F[rs2]{64}, F[rs3]{64}, zext(3, 32), choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FADD.D {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f + F[rs2]f;
val res[64] <= fdispatch_fadd_d(F[rs1]{64}, F[rs2]{64}, choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSUB.D {
encoding: b0000101 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f - F[rs2]f;
val res[64] <= fdispatch_fsub_d(F[rs1]{64}, F[rs2]{64}, choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMUL.D {
encoding: b0001001 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f * F[rs2]f;
val res[64] <= fdispatch_fmul_d(F[rs1]{64}, F[rs2]{64}, choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FDIV.D {
encoding: b0001101 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f / F[rs2]f;
val res[64] <= fdispatch_fdiv_d(F[rs1]{64}, F[rs2]{64}, choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSQRT.D {
encoding: b0101101 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
//F[rd]f<=sqrt(F[rs1]f);
val res[64] <= fdispatch_fsqrt_d(F[rs1]{64}, choose(rm<7, rm{8}, FCSR{8}));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSGNJ.D {
encoding: b0010001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
val ONE[64] <= 1;
val MSK1[64] <= ONE<<63;
val MSK2[64] <= MSK1-1;
val res[64] <= (F[rs1]{64} & MSK2) | (F[rs2]{64} & MSK1);
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FSGNJN.D {
encoding: b0010001 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
val ONE[64] <= 1;
val MSK1[64] <= ONE<<63;
val MSK2[64] <= MSK1-1;
val res[64] <= (F[rs1]{64} & MSK2) | (~F[rs2]{64} & MSK1);
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FSGNJX.D {
encoding: b0010001 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
val ONE[64] <= 1;
val MSK1[64] <= ONE<<63;
val res[64] <= F[rs1]{64} ^ (F[rs2]{64} & MSK1);
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FMIN.D {
encoding: b0010101 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
//F[rd]f<= choose(F[rs1]f<F[rs2]f, F[rs1]f, F[rs2]f);
val res[64] <= fdispatch_fsel_d(F[rs1]{64}, F[rs2]{64}, zext(0, 32));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMAX.D {
encoding: b0010101 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
//F[rd]f<= choose(F[rs1]f>F[rs2]f, F[rs1]f, F[rs2]f);
val res[64] <= fdispatch_fsel_d(F[rs1]{64}, F[rs2]{64}, zext(1, 32));
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.S.D {
encoding: b0100000 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}";
val res[32] <= fdispatch_fconv_d2f(F[rs1], rm{8});
// NaN boxing
val upper[FLEN] <= -1;
F[rd] <= upper<<32 | zext(res, FLEN);
}
FCVT.D.S {
encoding: b0100001 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}";
val res[64] <= fdispatch_fconv_f2d(F[rs1]{32}, rm{8});
if(FLEN==64){
F[rd] <= res;
} else {
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FEQ.D {
encoding: b1010001 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
X[rd]<=zext(fdispatch_fcmp_d(F[rs1]{64}, F[rs2]{64}, zext(0, 32)));
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FLT.D {
encoding: b1010001 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
X[rd]<=zext(fdispatch_fcmp_d(F[rs1]{64}, F[rs2]{64}, zext(2, 32)));
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FLE.D {
encoding: b1010001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
X[rd]<=zext(fdispatch_fcmp_d(F[rs1]{64}, F[rs2]{64}, zext(1, 32)));
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCLASS.D {
encoding: b1110001 | b00000 | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<=fdispatch_fclass_d(F[rs1]{64});
}
FCVT.W.D {
encoding: b1100001 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<= sext(fdispatch_fcvt_64_32(F[rs1]{64}, zext(0, 32), rm{8}), XLEN);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.WU.D {
encoding: b1100001 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
//FIXME: should be zext accodring to spec but needs to be sext according to tests
X[rd]<= sext(fdispatch_fcvt_64_32(F[rs1]{64}, zext(1, 32), rm{8}), XLEN);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.D.W {
encoding: b1101001 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
val res[64] <= fdispatch_fcvt_32_64(sext(X[rs1]{32},64), zext(2, 32), rm{8});
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FCVT.D.WU {
encoding: b1101001 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
val res[64] <=fdispatch_fcvt_32_64(zext(X[rs1]{32},64), zext(3,32), rm{8});
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
}
}
InsructionSet RV64D extends RV32D{
instructions{
FCVT.L.D {
encoding: b1100001 | b00010 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<= sext(fdispatch_fcvt_d(F[rs1]{64}, zext(0, 32), rm{8}), XLEN);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.LU.D {
encoding: b1100001 | b00011 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<= sext(fdispatch_fcvt_d(F[rs1]{64}, zext(1, 32), rm{8}), XLEN);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.D.L {
encoding: b1101001 | b00010 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
val res[64] <= fdispatch_fcvt_d(sext(X[rs1],64), zext(2, 32), rm{8});
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FCVT.D.LU {
encoding: b1101001 | b00011 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
val res[64] <=fdispatch_fcvt_d(zext(X[rs1],64), zext(3,32), rm{8});
if(FLEN==64)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<64) | res;
}
}
FMV.X.D {
encoding: b1110001 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<=sext(F[rs1]);
}
FMV.D.X {
encoding: b1111001 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
F[rd] <= zext(X[rs1]);
}
}
}

View File

@ -1,400 +0,0 @@
import "RV32I.core_desc"
InsructionSet RV32F extends RV32I{
constants {
FLEN, FFLAG_MASK := 0x1f
}
registers {
[31:0] F[FLEN], FCSR[32]
}
instructions{
FLW {
encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0000111;
args_disass:"f{rd}, {imm}(x{rs1})";
val offs[XLEN] <= X[rs1]'s + imm;
val res[32] <= MEM[offs]{32};
if(FLEN==32)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FSW {
encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b010 | imm[4:0]s | b0100111;
args_disass:"f{rs2}, {imm}(x{rs1})";
val offs[XLEN] <= X[rs1]'s + imm;
MEM[offs]{32}<=F[rs2]{32};
}
FMADD.S {
encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000011;
args_disass:"x{rd}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<= F[rs1]f * F[rs2]f + F[rs3]f;
if(FLEN==32)
F[rd] <= fdispatch_fmadd_s(F[rs1], F[rs2], F[rs3], zext(0, 32), choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val frs3[32] <= fdispatch_unbox_s(F[rs3]);
val res[32] <= fdispatch_fmadd_s(frs1, frs2, frs3, zext(0, 32), choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMSUB.S {
encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000111;
args_disass:"x{rd}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=F[rs1]f * F[rs2]f - F[rs3]f;
if(FLEN==32)
F[rd] <= fdispatch_fmadd_s(F[rs1], F[rs2], F[rs3], zext(1, 32), choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val frs3[32] <= fdispatch_unbox_s(F[rs3]);
val res[32] <= fdispatch_fmadd_s(frs1, frs2, frs3, zext(1, 32), choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FNMADD.S {
encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001111;
args_disass:"x{rd}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=-F[rs1]f * F[rs2]f + F[rs3]f;
if(FLEN==32)
F[rd] <= fdispatch_fmadd_s(F[rs1], F[rs2], F[rs3], zext(2, 32), choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val frs3[32] <= fdispatch_unbox_s(F[rs3]);
val res[32] <= fdispatch_fmadd_s(frs1, frs2, frs3, zext(2, 32), choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FNMSUB.S {
encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001011;
args_disass:"x{rd}, f{rs1}, f{rs2}, f{rs3}";
//F[rd]f<=-F[rs1]f * F[rs2]f - F[rs3]f;
if(FLEN==32)
F[rd] <= fdispatch_fmadd_s(F[rs1], F[rs2], F[rs3], zext(3, 32), choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val frs3[32] <= fdispatch_unbox_s(F[rs3]);
val res[32] <= fdispatch_fmadd_s(frs1, frs2, frs3, zext(3, 32), choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FADD.S {
encoding: b0000000 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f + F[rs2]f;
if(FLEN==32)
F[rd] <= fdispatch_fadd_s(F[rs1], F[rs2], choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fadd_s(frs1, frs2, choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSUB.S {
encoding: b0000100 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f - F[rs2]f;
if(FLEN==32)
F[rd] <= fdispatch_fsub_s(F[rs1], F[rs2], choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fsub_s(frs1, frs2, choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMUL.S {
encoding: b0001000 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f * F[rs2]f;
if(FLEN==32)
F[rd] <= fdispatch_fmul_s(F[rs1], F[rs2], choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fmul_s(frs1, frs2, choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FDIV.S {
encoding: b0001100 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
// F[rd]f <= F[rs1]f / F[rs2]f;
if(FLEN==32)
F[rd] <= fdispatch_fdiv_s(F[rs1], F[rs2], choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fdiv_s(frs1, frs2, choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSQRT.S {
encoding: b0101100 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}";
//F[rd]f<=sqrt(F[rs1]f);
if(FLEN==32)
F[rd] <= fdispatch_fsqrt_s(F[rs1], choose(rm<7, rm{8}, FCSR{8}));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val res[32] <= fdispatch_fsqrt_s(frs1, choose(rm<7, rm{8}, FCSR{8}));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FSGNJ.S {
encoding: b0010000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
if(FLEN==32)
F[rd] <= (F[rs1] & 0x7fffffff) | (F[rs2] & 0x80000000);
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= (frs1 & 0x7fffffff) | (frs2 & 0x80000000);
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FSGNJN.S {
encoding: b0010000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
if(FLEN==32)
F[rd] <= (F[rs1] & 0x7fffffff) | (~F[rs2] & 0x80000000);
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= (frs1 & 0x7fffffff) | (~frs2 & 0x80000000);
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FSGNJX.S {
encoding: b0010000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
if(FLEN==32)
F[rd] <= F[rs1] ^ (F[rs2] & 0x80000000);
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= frs1 ^ (frs2 & 0x80000000);
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FMIN.S {
encoding: b0010100 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
//F[rd]f<= choose(F[rs1]f<F[rs2]f, F[rs1]f, F[rs2]f);
if(FLEN==32)
F[rd] <= fdispatch_fsel_s(F[rs1], F[rs2], zext(0, 32));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fsel_s(frs1, frs2, zext(0, 32));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FMAX.S {
encoding: b0010100 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"f{rd}, f{rs1}, f{rs2}";
//F[rd]f<= choose(F[rs1]f>F[rs2]f, F[rs1]f, F[rs2]f);
if(FLEN==32)
F[rd] <= fdispatch_fsel_s(F[rs1], F[rs2], zext(1, 32));
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
val res[32] <= fdispatch_fsel_s(frs1, frs2, zext(1, 32));
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.W.S {
encoding: b1100000 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
if(FLEN==32)
X[rd] <= sext(fdispatch_fcvt_s(F[rs1], zext(0, 32), rm{8}), XLEN);
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
X[rd]<= sext(fdispatch_fcvt_s(frs1, zext(0, 32), rm{8}), XLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.WU.S {
encoding: b1100000 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
//FIXME: according to the spec it should be zero-extended not sign extended
if(FLEN==32)
X[rd]<= sext(fdispatch_fcvt_s(F[rs1], zext(1, 32), rm{8}), XLEN);
else { // NaN boxing
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
X[rd]<= sext(fdispatch_fcvt_s(frs1, zext(1, 32), rm{8}), XLEN);
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FEQ.S {
encoding: b1010000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
if(FLEN==32)
X[rd]<=zext(fdispatch_fcmp_s(F[rs1], F[rs2], zext(0, 32)));
else {
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
X[rd]<=zext(fdispatch_fcmp_s(frs1, frs2, zext(0, 32)));
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FLT.S {
encoding: b1010000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
if(FLEN==32)
X[rd]<=zext(fdispatch_fcmp_s(F[rs1], F[rs2], zext(2, 32)));
else {
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
X[rd]<=zext(fdispatch_fcmp_s(frs1, frs2, zext(2, 32)));
}
X[rd]<=fdispatch_fcmp_s(F[rs1]{32}, F[rs2]{32}, zext(2, 32));
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FLE.S {
encoding: b1010000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}, f{rs2}";
if(FLEN==32)
X[rd]<=zext(fdispatch_fcmp_s(F[rs1], F[rs2], zext(1, 32)));
else {
val frs1[32] <= fdispatch_unbox_s(F[rs1]);
val frs2[32] <= fdispatch_unbox_s(F[rs2]);
X[rd]<=zext(fdispatch_fcmp_s(frs1, frs2, zext(1, 32)));
}
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCLASS.S {
encoding: b1110000 | b00000 | rs1[4:0] | b001 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<=fdispatch_fclass_s(fdispatch_unbox_s(F[rs1]));
}
FCVT.S.W {
encoding: b1101000 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
if(FLEN==32)
F[rd] <= fdispatch_fcvt_s(X[rs1]{32}, zext(2, 32), rm{8});
else { // NaN boxing
val res[32] <= fdispatch_fcvt_s(X[rs1]{32}, zext(2, 32), rm{8});
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FCVT.S.WU {
encoding: b1101000 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
if(FLEN==32)
F[rd] <=fdispatch_fcvt_s(X[rs1]{32}, zext(3,32), rm{8});
else { // NaN boxing
val res[32] <=fdispatch_fcvt_s(X[rs1]{32}, zext(3,32), rm{8});
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FMV.X.W {
encoding: b1110000 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"{name(rd)}, f{rs1}";
X[rd]<=sext(F[rs1]{32});
}
FMV.W.X {
encoding: b1111000 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011;
args_disass:"f{rd}, {name(rs1)}";
if(FLEN==32)
F[rd] <= X[rs1]{32};
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(X[rs1]{32}, FLEN);
}
}
}
}
InsructionSet RV64F extends RV32F{
instructions{
FCVT.L.S { // fp to 64bit signed integer
encoding: b1100000 | b00010 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"x{rd}, f{rs1}";
val res[64] <= fdispatch_fcvt_32_64(fdispatch_unbox_s(F[rs1]), zext(0, 32), rm{8});
X[rd]<= sext(res);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.LU.S { // fp to 64bit unsigned integer
encoding: b1100000 | b00011 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"x{rd}, f{rs1}";
val res[64] <= fdispatch_fcvt_32_64(fdispatch_unbox_s(F[rs1]), zext(1, 32), rm{8});
X[rd]<= zext(res);
val flags[32] <= fdispatch_fget_flags();
FCSR <= (FCSR & ~FFLAG_MASK) + flags{5};
}
FCVT.S.L { // 64bit signed int to to fp
encoding: b1101000 | b00010 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, x{rs1}";
val res[32] <= fdispatch_fcvt_64_32(X[rs1], zext(2, 32));
if(FLEN==32)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
FCVT.S.LU { // 64bit unsigned int to to fp
encoding: b1101000 | b00011 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011;
args_disass:"f{rd}, x{rs1}";
val res[32] <=fdispatch_fcvt_64_32(X[rs1], zext(3,32));
if(FLEN==32)
F[rd] <= res;
else { // NaN boxing
val upper[FLEN] <= -1;
F[rd] <= (upper<<32) | zext(res, FLEN);
}
}
}
}

View File

@ -1,160 +0,0 @@
import "RISCVBase.core_desc"
InsructionSet RV32M extends RISCVBase {
constants {
MAXLEN:=128
}
instructions{
MUL{
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val res[MAXLEN] <= zext(X[rs1], MAXLEN) * zext(X[rs2], MAXLEN);
X[rd]<= zext(res , XLEN);
}
}
MULH {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val res[MAXLEN] <= sext(X[rs1], MAXLEN) * sext(X[rs2], MAXLEN);
X[rd]<= zext(res >> XLEN, XLEN);
}
}
MULHSU {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val res[MAXLEN] <= sext(X[rs1], MAXLEN) * zext(X[rs2], MAXLEN);
X[rd]<= zext(res >> XLEN, XLEN);
}
}
MULHU {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
val res[MAXLEN] <= zext(X[rs1], MAXLEN) * zext(X[rs2], MAXLEN);
X[rd]<= zext(res >> XLEN, XLEN);
}
}
DIV {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0){
val M1[XLEN] <= -1;
val XLM1[8] <= XLEN-1;
val ONE[XLEN] <= 1;
val MMIN[XLEN] <= ONE<<XLM1;
if(X[rs1]==MMIN && X[rs2]==M1)
X[rd] <= MMIN;
else
X[rd] <= X[rs1]s / X[rs2]s;
}else
X[rd] <= -1;
}
}
DIVU {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0)
X[rd] <= X[rs1] / X[rs2];
else
X[rd] <= -1;
}
}
REM {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0) {
val M1[XLEN] <= -1; // constant -1
val XLM1[32] <= XLEN-1;
val ONE[XLEN] <= 1;
val MMIN[XLEN] <= ONE<<XLM1; // -2^(XLEN-1)
if(X[rs1]==MMIN && X[rs2]==M1)
X[rd] <= 0;
else
X[rd] <= X[rs1]'s % X[rs2]'s;
} else
X[rd] <= X[rs1];
}
}
REMU {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0110011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0)
X[rd] <= X[rs1] % X[rs2];
else
X[rd] <= X[rs1];
}
}
}
}
InsructionSet RV64M extends RV32M {
instructions{
MULW{
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
X[rd]<= sext(X[rs1]{32} * X[rs2]{32});
}
}
DIVW {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0){
val M1[32] <= -1;
val ONE[32] <= 1;
val MMIN[32] <= ONE<<31;
if(X[rs1]{32}==MMIN && X[rs2]{32}==M1)
X[rd] <= -1<<31;
else
X[rd] <= sext(X[rs1]{32}s / X[rs2]{32}s);
}else
X[rd] <= -1;
}
}
DIVUW {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]{32}!=0)
X[rd] <= sext(X[rs1]{32} / X[rs2]{32});
else
X[rd] <= -1;
}
}
REMW {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]!=0) {
val M1[32] <= -1; // constant -1
val ONE[32] <= 1;
val MMIN[32] <= ONE<<31; // -2^(XLEN-1)
if(X[rs1]{32}==MMIN && X[rs2]==M1)
X[rd] <= 0;
else
X[rd] <= sext(X[rs1]{32}s % X[rs2]{32}s);
} else
X[rd] <= sext(X[rs1]{32});
}
}
REMUW {
encoding: b0000001 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0111011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
if(rd != 0){
if(X[rs2]{32}!=0)
X[rd] <= sext(X[rs1]{32} % X[rs2]{32});
else
X[rd] <= sext(X[rs1]{32});
}
}
}
}

37
gen_input/TGFS.core_desc Normal file
View File

@ -0,0 +1,37 @@
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
Core TGC_B provides RV32I {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000000000100000000;
unsigned PGSIZE = 0x1000; //1 << 12;
unsigned PGMASK = 0xfff; //PGSIZE-1
}
}
Core TGC_C provides RV32I, RV32M, RV32IC {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100;
unsigned PGSIZE = 0x1000; //1 << 12;
unsigned PGMASK = 0xfff; //PGSIZE-1
}
}
Core TGC_D provides RV32I, RV32M, RV32IC {
architectural_state {
unsigned XLEN=32;
unsigned PCLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100;
}
}

View File

@ -1,70 +0,0 @@
import "RV32I.core_desc"
import "RV64I.core_desc"
import "RVM.core_desc"
import "RVA.core_desc"
import "RVC.core_desc"
import "RVF.core_desc"
import "RVD.core_desc"
Core MNRV32 provides RV32I, RV32IC {
constants {
XLEN:=32;
PCLEN:=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b01000000000101000001000100000101;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}
/*
Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC {
constants {
XLEN:=32;
PCLEN:=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b01000000000101000001000100000101;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}
Core RV32GC provides RV32I, RV32M, RV32A, RV32F, RV32D, RV32IC, RV32FC, RV32DC {
constants {
XLEN:=32;
FLEN:=64;
PCLEN:=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b01000000000101000001000100101101;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}
Core RV64I provides RV64I {
constants {
XLEN:=64;
PCLEN:=64;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b10000000000001000000000100000000;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}
Core RV64GC provides RV64I, RV64M, RV64A, RV64F, RV64D, RV64IC, RV32FC, RV32DC {
constants {
XLEN:=64;
FLEN:=64;
PCLEN:=64;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b01000000000101000001000100101101;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}
*/

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,51 +29,48 @@
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
def getRegisterSizes(){
def regs = registers.collect{it.size}
regs[-1]=64 // correct for NEXT_PC
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/mnrv32.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::mnrv32>::reg_names;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::mnrv32>::reg_aliases;
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::mnrv32>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::mnrv32>::reg_byte_offsets;
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
mnrv32::mnrv32() {
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
mnrv32::~mnrv32() = default;
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void mnrv32::reset(uint64_t address) {
for(size_t i=0; i<traits<mnrv32>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<mnrv32>::reg_t),0));
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.PRIV=0x3;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *mnrv32::get_regs_base_ptr() {
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
mnrv32::phys_addr_t mnrv32::virt2phys(const iss::addr_t &pc) {
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* Copyright (C) 2017 - 2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,47 +29,38 @@
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.util.BigIntegerWithRadix
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getTypeSize(size){
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
}
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
def getRegisterSizes(){
def regs = registers.collect{nativeTypeSize(it.size)}
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
def getRegisterOffsets(){
def offset = 0
def offsets = []
getRegisterSizes().each { size ->
offsets<<offset
offset+=size/8
}
return offsets
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
def byteSize(int size){
if(size<=8) return 8;
if(size<=16) return 16;
if(size<=32) return 32;
if(size<=64) return 64;
return 128;
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
def getCString(def val){
if(val instanceof BigIntegerWithRadix)
return ((BigIntegerWithRadix)val).toCString()
else
return val.toString()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
@ -87,43 +78,28 @@ struct ${coreDef.name.toLowerCase()};
template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}";
constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
{"${getRegisterNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${registers.size}> reg_names{
{"${registers.collect{it.name}.join('", "')}"}};
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${registers.size}> reg_aliases{
{"${registers.collect{it.alias}.join('", "')}"}};
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
${reg.name}${it},<%
}
} else if(reg instanceof Register){ %>
${reg.name},<%
}
}%>
NUM_REGS,
NEXT_${pc.name}=NUM_REGS,
TRAP_STATE,
enum reg_e {
${registers.collect{it.name}.join(', ')}, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
ICOUNT,
CYCLE,
INSTRET
};
using reg_t = uint${regDataWidth}_t;
using reg_t = uint${addrDataWidth}_t;
using addr_t = uint${addrDataWidth}_t;
@ -133,17 +109,22 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};
static constexpr std::array<const uint32_t, ${getRegisterSizes().size}> reg_bit_widths{
{${getRegisterSizes().join(',')}}};
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.join(",")}}};
static constexpr std::array<const uint32_t, ${getRegisterOffsets().size}> reg_byte_offsets{
{${getRegisterOffsets().join(',')}}};
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 { ${allSpaces.collect{s -> s.name}.join(', ')} };
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
${instr.instruction.name} = ${index},<%}%>
MAX_OPCODE
};
};
struct ${coreDef.name.toLowerCase()}: public arch_if {
@ -172,6 +153,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
@ -187,32 +170,29 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1)
struct ${coreDef.name}_regs {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
}
} else if(reg instanceof Register){ %>
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
}
}%>
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
registers.each { reg -> if(reg.size>0) {%>
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
}}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;
#pragma pack(pop)
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
def fcsr = registers.find {it.name=='FCSR'}
if(fcsr != null) {%>
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
uint${fcsr.size}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${fcsr.size}_t val){reg.FCSR = val;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};

View File

@ -0,0 +1,342 @@
/*******************************************************************************
* Copyright (C) 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.
*
*******************************************************************************/
#include "../fp_functions.h"
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/interp/vm_base.h>
#include <util/logging.h>
#include <sstream>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace interp {
namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
public:
using traits = arch::traits<ARCH>;
using super = typename iss::interp::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
using reg_t = typename traits::reg_t;
using mem_type_e = typename traits::mem_type_e;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (super::tgt_adapter == nullptr)
super::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return super::tgt_adapter;
}
protected:
using this_class = vm_impl<ARCH>;
using compile_ret_t = virt_addr_t;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
compile_func decode_inst(code_word_t instr) ;
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
struct instruction_pattern {
uint32_t value;
uint32_t mask;
compile_func opc;
};
std::array<std::vector<instruction_pattern>, 4> qlut;
inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
}
inline void leave(unsigned lvl){
this->core.leave_trap(lvl);
}
inline void wait(unsigned type){
this->core.wait_until(type);
}
template<typename T>
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint8_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint16_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint32_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint64_t>(space, addr);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
return ret;
}
inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){
super::write_mem(space, addr, data);
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) {
auto mask = (1ULL<<W) - 1;
auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
// pre execution stuff
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*PC=*NEXT_PC;
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
*trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */
<%instr.disass.eachLine{%>${it}
<%}%>
}
// used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%>
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction
try {
<%instr.behavior.eachLine{%>${it}
<%}%>} catch(...){}
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
} else {
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++;
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++;
}
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
pc.val=*NEXT_PC;
return pc;
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
raise(0, 2);
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
}
pc.val=*NEXT_PC;
return pc;
}
static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
auto phys_pc = this->core.v2p(pc);
//if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
//} else {
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
//}
return iss::Ok;
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
// according to
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
#ifdef __GCC__
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
#elif __cplusplus < 201402L
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
#else
constexpr size_t bit_count(uint32_t u) {
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
#endif
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
for (auto instr : instr_descr) {
auto quadrant = instr.value & 0x3;
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
}
for(auto& lut: qlut){
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
return bit_count(a.mask) > bit_count(b.mask);
});
}
}
inline bool is_count_limit_enabled(finish_cond_e cond){
return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT;
}
inline bool is_jump_to_self_enabled(finish_cond_e cond){
return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
}
template <typename ARCH>
typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
for(auto& e: qlut[instr&0x3]){
if(!((instr&e.mask) ^ e.value )) return e.opc;
}
return &this_class::illegal_intruction;
}
template <typename ARCH>
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
// we fetch at max 4 byte, alignment is 2
code_word_t insn = 0;
auto *const data = (uint8_t *)&insn;
auto pc=start;
while(!this->core.should_stop() &&
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
auto res = fetch_ins(pc, data);
if(res!=iss::Ok){
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
} else {
if (is_jump_to_self_enabled(cond) &&
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto f = decode_inst(insn);
pc = (this->*f)(pc, insn);
}
}
return pc;
}
} // namespace mnrv32
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
} // namespace interp
} // namespace iss

View File

@ -1,117 +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.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -1,246 +0,0 @@
/*******************************************************************************
* Copyright (C) 2020 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.
*
*******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/interp/vm_base.h>
#include <util/logging.h>
#include <sstream>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace interp {
namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
public:
using super = typename iss::interp::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
using reg_t = typename traits<ARCH>::reg_t;
using iss::interp::vm_base<ARCH>::get_reg;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (super::tgt_adapter == nullptr)
super::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return super::tgt_adapter;
}
protected:
using this_class = vm_impl<ARCH>;
using compile_ret_t = virt_addr_t;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
virt_addr_t execute_inst(virt_addr_t start, std::function<bool(void)> pred) override;
// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
std::array<compile_func *, 4> qlut;
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}
void raise_trap(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->template get_reg<uint32_t>(arch::traits<ARCH>::TRAP_STATE) = trap_val;
this->template get_reg<uint32_t>(arch::traits<ARCH>::NEXT_PC) = std::numeric_limits<uint32_t>::max();
}
void leave_trap(unsigned lvl){
this->core.leave_trap(lvl);
auto pc_val = super::template read_mem<reg_t>(traits<ARCH>::CSR, (lvl << 8) + 0x41);
this->template get_reg<reg_t>(arch::traits<ARCH>::NEXT_PC) = pc_val;
this->template get_reg<uint32_t>(arch::traits<ARCH>::LAST_BRANCH) = std::numeric_limits<uint32_t>::max();
}
void wait(unsigned type){
this->core.wait_until(type);
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){<%instr.code.eachLine{%>
${it}<%}%>
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
pc = pc + ((instr & 3) == 3 ? 4 : 2);
return pc;
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}
template <typename ARCH>
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(virt_addr_t start, std::function<bool(void)> pred) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
code_word_t insn = 0;
auto *const data = (uint8_t *)&insn;
auto pc=start;
while(pred){
auto paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) // this is a 32bit instruction
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
} else {
if (this->core.read(paddr, 4, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (!f)
f = &this_class::illegal_intruction;
pc = (this->*f)(pc, insn);
}
return pc;
}
} // namespace mnrv32
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
} // namespace interp
} // namespace iss

View File

@ -172,6 +172,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
@ -204,7 +206,7 @@ protected:
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
if(fcsr != null) {%>

View File

@ -70,17 +70,7 @@ def getRegisterAliasNames(){
%>
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>

View File

@ -31,7 +31,7 @@
*******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
@ -57,7 +57,7 @@ using namespace ::llvm;
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public vm::llvm::vm_base<ARCH> {
template <typename ARCH> class vm_impl : public iss::llvm::vm_base<ARCH> {
public:
using super = typename iss::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;

View File

@ -70,17 +70,7 @@ def getRegisterAliasNames(){
%>
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>

View File

@ -31,7 +31,7 @@
*******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
@ -184,8 +184,8 @@ private:
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, 0b${instr.value}, 0b${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>

1
incl/iss/arch/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/tgc_*.h

View File

@ -1,252 +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.
*
*******************************************************************************/
#ifndef _MNRV32_H_
#define _MNRV32_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct mnrv32;
template <> struct traits<mnrv32> {
constexpr static char const* const core_type = "MNRV32";
static constexpr std::array<const char*, 33> 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"}};
static constexpr std::array<const char*, 33> 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"}};
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000101000001000100000101, PGSIZE=0x1000, PGMASK=0xfff};
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,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};
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<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 39> 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,32,32,32,32,64}};
static constexpr std::array<const uint32_t, 40> 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,140,144,148,152,160}};
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, CSR, FENCE, RES };
};
struct mnrv32: public arch_if {
using virt_addr_t = typename traits<mnrv32>::virt_addr_t;
using phys_addr_t = typename traits<mnrv32>::phys_addr_t;
using reg_t = typename traits<mnrv32>::reg_t;
using addr_t = typename traits<mnrv32>::addr_t;
mnrv32();
~mnrv32();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<mnrv32>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<mnrv32>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
struct MNRV32_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;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
};
}
}
#endif /* _MNRV32_H_ */

View File

@ -0,0 +1,242 @@
/*******************************************************************************
* Copyright (C) 2017, 2018, 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.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON
#include "iss/arch_if.h"
#include <cstdint>
namespace iss {
namespace arch {
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
enum riscv_csr {
/* user-level CSR */
// User Trap Setup
ustatus = 0x000,
uie = 0x004,
utvec = 0x005,
// User Trap Handling
uscratch = 0x040,
uepc = 0x041,
ucause = 0x042,
utval = 0x043,
uip = 0x044,
// User Floating-Point CSRs
fflags = 0x001,
frm = 0x002,
fcsr = 0x003,
// User Counter/Timers
cycle = 0xC00,
time = 0xC01,
instret = 0xC02,
hpmcounter3 = 0xC03,
hpmcounter4 = 0xC04,
/*...*/
hpmcounter31 = 0xC1F,
cycleh = 0xC80,
timeh = 0xC81,
instreth = 0xC82,
hpmcounter3h = 0xC83,
hpmcounter4h = 0xC84,
/*...*/
hpmcounter31h = 0xC9F,
/* supervisor-level CSR */
// Supervisor Trap Setup
sstatus = 0x100,
sedeleg = 0x102,
sideleg = 0x103,
sie = 0x104,
stvec = 0x105,
scounteren = 0x106,
// Supervisor Trap Handling
sscratch = 0x140,
sepc = 0x141,
scause = 0x142,
stval = 0x143,
sip = 0x144,
// Supervisor Protection and Translation
satp = 0x180,
/* machine-level CSR */
// Machine Information Registers
mvendorid = 0xF11,
marchid = 0xF12,
mimpid = 0xF13,
mhartid = 0xF14,
// Machine Trap Setup
mstatus = 0x300,
misa = 0x301,
medeleg = 0x302,
mideleg = 0x303,
mie = 0x304,
mtvec = 0x305,
mcounteren = 0x306,
mtvt = 0x307, //CLIC
// Machine Trap Handling
mscratch = 0x340,
mepc = 0x341,
mcause = 0x342,
mtval = 0x343,
mip = 0x344,
mxnti = 0x345, //CLIC
mintstatus = 0x346, // MRW Current interrupt levels (CLIC) - addr subject to change
mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
mscratchcswl = 0x349, // MRW Conditional scratch swap on level change (CLIC)
mintthresh = 0x350, // MRW Interrupt-level threshold (CLIC) - addr subject to change
mclicbase = 0x351, // MRW Base address for CLIC memory mapped registers (CLIC) - addr subject to change
// Physical Memory Protection
pmpcfg0 = 0x3A0,
pmpcfg1 = 0x3A1,
pmpcfg2 = 0x3A2,
pmpcfg3 = 0x3A3,
pmpaddr0 = 0x3B0,
pmpaddr1 = 0x3B1,
pmpaddr2 = 0x3B2,
pmpaddr3 = 0x3B3,
pmpaddr4 = 0x3B4,
pmpaddr5 = 0x3B5,
pmpaddr6 = 0x3B6,
pmpaddr7 = 0x3B7,
pmpaddr8 = 0x3B8,
pmpaddr9 = 0x3B9,
pmpaddr10 = 0x3BA,
pmpaddr11 = 0x3BB,
pmpaddr12 = 0x3BC,
pmpaddr13 = 0x3BD,
pmpaddr14 = 0x3BE,
pmpaddr15 = 0x3BF,
// Machine Counter/Timers
mcycle = 0xB00,
minstret = 0xB02,
mhpmcounter3 = 0xB03,
mhpmcounter4 = 0xB04,
/*...*/
mhpmcounter31 = 0xB1F,
mcycleh = 0xB80,
minstreth = 0xB82,
mhpmcounter3h = 0xB83,
mhpmcounter4h = 0xB84,
/*...*/
mhpmcounter31h = 0xB9F,
// Machine Counter Setup
mhpmevent3 = 0x323,
mhpmevent4 = 0x324,
/*...*/
mhpmevent31 = 0x33F,
// Debug/Trace Registers (shared with Debug Mode)
tselect = 0x7A0,
tdata1 = 0x7A1,
tdata2 = 0x7A2,
tdata3 = 0x7A3,
// Debug Mode Registers
dcsr = 0x7B0,
dpc = 0x7B1,
dscratch = 0x7B2
};
enum {
PGSHIFT = 12,
PTE_PPN_SHIFT = 10,
// page table entry (PTE) fields
PTE_V = 0x001, // Valid
PTE_R = 0x002, // Read
PTE_W = 0x004, // Write
PTE_X = 0x008, // Execute
PTE_U = 0x010, // User
PTE_G = 0x020, // Global
PTE_A = 0x040, // Accessed
PTE_D = 0x080, // Dirty
PTE_SOFT = 0x300 // Reserved for Software
};
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
enum {
ISA_A = 1,
ISA_B = 1 << 1,
ISA_C = 1 << 2,
ISA_D = 1 << 3,
ISA_E = 1 << 4,
ISA_F = 1 << 5,
ISA_G = 1 << 6,
ISA_I = 1 << 8,
ISA_M = 1 << 12,
ISA_N = 1 << 13,
ISA_Q = 1 << 16,
ISA_S = 1 << 18,
ISA_U = 1 << 20
};
struct vm_info {
int levels;
int idxbits;
int ptesize;
uint64_t ptbase;
bool is_active() { return levels; }
};
class trap_load_access_fault : public trap_access {
public:
trap_load_access_fault(uint64_t badaddr)
: trap_access(5 << 16, badaddr) {}
};
class illegal_instruction_fault : public trap_access {
public:
illegal_instruction_fault(uint64_t badaddr)
: trap_access(2 << 16, badaddr) {}
};
class trap_instruction_page_fault : public trap_access {
public:
trap_instruction_page_fault(uint64_t badaddr)
: trap_access(12 << 16, badaddr) {}
};
class trap_load_page_fault : public trap_access {
public:
trap_load_page_fault(uint64_t badaddr)
: trap_access(13 << 16, badaddr) {}
};
class trap_store_page_fault : public trap_access {
public:
trap_store_page_fault(uint64_t badaddr)
: trap_access(15 << 16, badaddr) {}
};
}
}
#endif

View File

@ -0,0 +1,976 @@
/*******************************************************************************
* Copyright (C) 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.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_M_P_H
#define _RISCV_HART_M_P_H
#include "riscv_hart_common.h"
#include "iss/arch/traits.h"
#include "iss/instrumentation_if.h"
#include "iss/log_categories.h"
#include "iss/vm_if.h"
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <array>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iomanip>
#include <sstream>
#include <type_traits>
#include <unordered_map>
#include <functional>
#include <util/bit_field.h>
#include <util/ities.h>
#include <util/sparse_array.h>
#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 {
template <typename BASE> class riscv_hart_m_p : public BASE {
protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char *, 16> trap_str = {{""
"Instruction address misaligned", // 0
"Instruction access fault", // 1
"Illegal instruction", // 2
"Breakpoint", // 3
"Load address misaligned", // 4
"Load access fault", // 5
"Store/AMO address misaligned", // 6
"Store/AMO access fault", // 7
"Environment call from U-mode", // 8
"Environment call from S-mode", // 9
"Reserved", // a
"Environment call from M-mode", // b
"Instruction page fault", // c
"Load page fault", // d
"Reserved", // e
"Store/AMO page fault"}};
const std::array<const char *, 12> irq_str = {
{"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
public:
using core = BASE;
using this_class = riscv_hart_m_p<BASE>;
using phys_addr_t = typename core::phys_addr_t;
using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t;
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
// primary template
template <class T, class Enable = void> struct hart_state {};
// specialization 32bit
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint32_t>::value>::type> {
public:
BEGIN_BF_DECL(mstatus_t, T);
// SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11)))
BF_FIELD(SD, 31, 1);
// Trap SRET
BF_FIELD(TSR, 22, 1);
// Timeout Wait
BF_FIELD(TW, 21, 1);
// Trap Virtual Memory
BF_FIELD(TVM, 20, 1);
// Make eXecutable Readable
BF_FIELD(MXR, 19, 1);
// permit Supervisor User Memory access
BF_FIELD(SUM, 18, 1);
// Modify PRiVilege
BF_FIELD(MPRV, 17, 1);
// status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
BF_FIELD(XS, 15, 2);
// floating-point unit status Off/Initial/Clean/Dirty
BF_FIELD(FS, 13, 2);
// machine previous privilege
BF_FIELD(MPP, 11, 2);
// supervisor previous privilege
BF_FIELD(SPP, 8, 1);
// previous machine interrupt-enable
BF_FIELD(MPIE, 7, 1);
// previous supervisor interrupt-enable
BF_FIELD(SPIE, 5, 1);
// previous user interrupt-enable
BF_FIELD(UPIE, 4, 1);
// machine interrupt-enable
BF_FIELD(MIE, 3, 1);
// supervisor interrupt-enable
BF_FIELD(SIE, 1, 1);
// user interrupt-enable
BF_FIELD(UIE, 0, 1);
END_BF_DECL();
mstatus_t mstatus;
static const reg_t mstatus_reset_val = 0x1800;
void write_mstatus(T val) {
auto mask = get_mask() &0xff; // MPP is hardcode as 0x3
auto new_val = (mstatus.backing.val & ~mask) | (val & mask);
mstatus = new_val;
}
static constexpr uint32_t get_mask() {
//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;
}
};
using hart_state_type = hart_state<reg_t>;
constexpr reg_t get_irq_mask() {
return 0b100010001000; // only machine mode is supported
}
constexpr reg_t get_pc_mask() {
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
}
riscv_hart_m_p();
virtual ~riscv_hart_m_p() = default;
void reset(uint64_t address) override;
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) 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) override;
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) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
pc, instr, (reg_t)state.mstatus, this->reg.icount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
mem_read_cb = memReadCb;
}
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
mem_write_cb = memWriteCb;
}
void set_csr(unsigned addr, reg_t val){
csr[addr & csr.page_addr_mask] = val;
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
riscv_instrumentation_if(riscv_hart_m_p<BASE> &arch)
: arch(arch) {}
/**
* get the name of this architecture
*
* @return the name of this architecture
*/
const std::string core_type_name() const override { return traits<BASE>::core_type; }
virtual uint64_t get_pc() { return arch.get_pc(); };
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
riscv_hart_m_p<BASE> &arch;
};
friend struct riscv_instrumentation_if;
addr_t get_pc() { return this->reg.PC; }
addr_t get_next_pc() { return this->reg.NEXT_PC; }
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
virtual iss::status read_csr(unsigned addr, reg_t &val);
virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state;
int64_t cycle_offset{0};
uint64_t mcycle_csr{0};
int64_t instret_offset{0};
uint64_t minstret_csr{0};
reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
unsigned to_host_wr_cnt = 0;
riscv_instrumentation_if instr_if;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
using csr_page_type = typename csr_type::page_type;
mem_type mem;
csr_type csr;
std::stringstream uart_buf;
std::unordered_map<reg_t, uint64_t> ptw;
std::unordered_map<uint64_t, uint8_t> atomic_reservation;
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
private:
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val);
iss::status read_tvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val);
iss::status write_cause(unsigned addr, reg_t val);
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 read_hartid(unsigned addr, reg_t &val);
iss::status write_epc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
protected:
void check_interrupt();
};
template <typename BASE>
riscv_hart_m_p<BASE>::riscv_hart_m_p()
: state()
, instr_if(*this) {
// reset values
csr[misa] = traits<BASE>::MISA_VAL;
csr[mvendorid] = 0x669;
csr[marchid] = 0x80000003;
csr[mimpid] = 1;
uart_buf.str("");
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
}
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
//csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
// special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
csr_rd_cb[timeh] = &this_class::read_time;
csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status;
csr_wr_cb[mcause] = &this_class::write_cause;
csr_rd_cb[mtvec] = &this_class::read_tvec;
csr_wr_cb[mepc] = &this_class::write_epc;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
csr_rd_cb[mcounteren] = &this_class::read_null;
csr_wr_cb[mcounteren] = &this_class::write_null;
csr_wr_cb[misa] = &this_class::write_null;
csr_wr_cb[mvendorid] = &this_class::write_null;
csr_wr_cb[marchid] = &this_class::write_null;
csr_wr_cb[mimpid] = &this_class::write_null;
}
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) {
FILE *fp = fopen(name.c_str(), "r");
if (fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
if (n != 4) throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if (strcmp(buf.data() + 1, "ELF") == 0) {
fclose(fp);
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if (!reader.load(name)) throw std::runtime_error("could not process elf file");
// check elf properties
if (reader.get_class() != ELFCLASS32)
if (sizeof(reg_t) == 4) throw std::runtime_error("wrong elf class in file");
if (reader.get_type() != ET_EXEC) throw std::runtime_error("wrong elf type in file");
if (reader.get_machine() != EM_RISCV) throw std::runtime_error("wrong elf machine in file");
auto entry = reader.get_entry();
for (const auto pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
if (fsize > 0) {
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE,
traits<BASE>::MEM, pseg->get_physical_address(),
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
if (res != iss::Ok)
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex
<< pseg->get_physical_address();
}
}
for(const auto sec : reader.sections) {
if(sec->get_name() == ".symtab") {
if ( SHT_SYMTAB == sec->get_type() ||
SHT_DYNSYM == sec->get_type() ) {
ELFIO::symbol_section_accessor symbols( reader, sec );
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for ( auto i = 0U; i < sym_no; ++i ) {
symbols.get_symbol( i, name, value, size, bind, type, section, other );
if(name=="tohost") {
tohost = value;
} else if(name=="fromhost") {
fromhost = value;
}
}
}
} else if (sec->get_name() == ".tohost") {
tohost = sec->get_address();
fromhost = tohost + 0x40;
}
}
return std::make_pair(entry, true);
}
throw std::runtime_error("memory load file is not a valid elf file");
}
throw std::runtime_error("memory load file not found");
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) {
#ifndef NDEBUG
if (access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH){
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
}
#endif
try {
switch (space) {
case traits<BASE>::MEM: {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err;
}
try {
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if(alignment>1 && (addr&(alignment-1))){
this->reg.trap_state = 1<<31 | 4<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)){
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
} break;
case traits<BASE>::CSR: {
if (length != sizeof(reg_t)) return iss::Err;
return read_csr(addr, *reinterpret_cast<reg_t *const>(data));
} break;
case traits<BASE>::FENCE: {
if ((addr + length) > mem.size()) return iss::Err;
return iss::Ok;
} break;
case traits<BASE>::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) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::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) {
#ifndef NDEBUG
const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch (length) {
case 8:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 4:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 2:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
case 1:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec
<< ") @addr 0x" << std::hex << addr;
break;
default:
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
}
#endif
try {
switch (space) {
case traits<BASE>::MEM: {
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err;
}
try {
if(!(access && iss::access_type::DEBUG) && length>1 && (addr&(length-1))){
this->reg.trap_state = 1<<31 | 6<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) {
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
if ((paddr.val + length) > mem.size()) return iss::Err;
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str("");
}
return iss::Ok;
case 0x10008000: { // HFROSC base, hfrosccfg reg
auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
auto &x = *(p.data() + offs + 3);
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
return iss::Ok;
}
case 0x10008008: { // HFROSC base, pllcfg reg
auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
auto &x = *(p.data() + offs + 3);
x |= 0x80; // set pll lock upon writing
return iss::Ok;
} break;
default: {}
}
} break;
case traits<BASE>::CSR: {
if (length != sizeof(reg_t)) return iss::Err;
return write_csr(addr, *reinterpret_cast<const reg_t *>(data));
} break;
case traits<BASE>::FENCE: {
if ((addr + length) > mem.size()) return iss::Err;
switch (addr) {
case 2:
case 3: {
ptw.clear();
auto tvm = state.mstatus.TVM;
return iss::Ok;
}
}
} break;
case traits<BASE>::RES: {
atomic_reservation[addr] = data[0];
} break;
default:
return iss::Err;
}
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
auto it = csr_rd_cb.find(addr);
if (it == csr_rd_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
if((addr&0xc00)==0xc00) // writing to read-only region
throw illegal_instruction_fault(this->fault_data);
auto it = csr_wr_cb.find(addr);
if (it == csr_wr_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned addr, reg_t &val) {
val = csr[addr];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_null(unsigned addr, reg_t &val) {
val = 0;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(cycle_val >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val);
} else {
if (addr == mcycle) {
mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
} else {
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
}
}
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->reg.instret--;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
val = csr[mtvec] & ~2;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
val = state.mstatus & hart_state_type::get_mask();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) {
state.write_mstatus(val);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cause(unsigned addr, reg_t val) {
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) {
val = csr[mie];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_hartid(unsigned addr, reg_t &val) {
val = mhartid_reg;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) {
auto mask = get_irq_mask();
csr[mie] = (csr[mie] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) {
val = csr[mip];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) {
auto mask = get_irq_mask();
mask &= ~(1 << 7); // MTIP is read only
csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask();
return iss::Ok;
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
if (sizeof(reg_t) < length) return iss::Err;
reg_t time_val;
this->read_csr(time, time_val);
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
} break;
case 0x10008000: {
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
uint64_t offs = paddr.val & mem.page_addr_mask;
std::copy(p.data() + offs, p.data() + offs + length, data);
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
}
}
}
return iss::Ok;
}
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str("");
}
break;
case 0x10008000: { // HFROSC base, hfrosccfg reg
mem_type::page_type &p = mem(paddr.val / mem.page_size);
size_t offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
uint8_t &x = *(p.data() + offs + 3);
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
} break;
case 0x10008008: { // HFROSC base, pllcfg reg
mem_type::page_type &p = mem(paddr.val / mem.page_size);
size_t offs = paddr.val & mem.page_addr_mask;
std::copy(data, data + length, p.data() + offs);
uint8_t &x = *(p.data() + offs + 3);
x |= 0x80; // set pll lock upon writing
} break;
default: {
mem_type::page_type &p = mem(paddr.val / mem.page_size);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) {
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
auto tohost_lower =
(traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
switch (hostvar >> 48) {
case 0:
if (hostvar != 0x1) {
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation";
} else {
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation";
}
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar;
break;
//throw(iss::simulation_stopped(hostvar));
case 0x0101: {
char c = static_cast<char>(hostvar & 0xff);
if (c == '\n' || c == 0) {
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str("");
} else
uart_buf << c;
to_host_wr_cnt = 0;
} break;
default:
break;
}
} else if (tohost_lower)
to_host_wr_cnt++;
} else if ((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) ||
(traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
}
}
}
}
return iss::Ok;
}
template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) {
BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val;
}
template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
//auto ideleg = csr[mideleg];
// 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 = csr[mip] & csr[mie];
bool mie = state.mstatus.MIE;
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
auto enabled_interrupts = m_enabled ? ena_irq : 0;
if (enabled_interrupts != 0) {
int res = 0;
while ((enabled_interrupts & 1) == 0) {
enabled_interrupts >>= 1;
res++;
}
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
}
}
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags);
auto cause = bit_sub<16, 15>(flags);
if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
// calculate effective privilege level
if (trap_id == 0) { // exception
// store ret addr in xepc register
csr[mepc] = static_cast<reg_t>(addr) & get_pc_mask(); // store actual address instruction of exception
csr[mtval] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0;
} else {
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
this->reg.pending_trap = 0;
}
csr[mcause] = (trap_id << 31) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus
// is written with the value of the active interrupt-enable bit at the time of
// the trap; and the x IE field of mstatus
// is cleared
// store the actual privilege level in yPP and store interrupt enable flags
state.mstatus.MPP = PRIV_M;
state.mstatus.MPIE = state.mstatus.MIE;
state.mstatus.MIE = false;
// get trap vector
auto ivec = csr[mtvec];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec
this->reg.NEXT_PC = ivec & ~0x3UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state
this->reg.PRIV = PRIV_M;
this->reg.trap_state = 0;
std::array<char, 32> buffer;
#if defined(_MSC_VER)
sprintf(buffer.data(), "0x%016llx", addr);
#else
sprintf(buffer.data(), "0x%016lx", addr);
#endif
if((flags&0xffffffff) != 0xffffffff)
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '"
<< (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")"
<< " at address " << buffer.data() << " occurred";
return this->reg.NEXT_PC;
}
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
state.mstatus.MIE = state.mstatus.MPIE;
state.mstatus.MPIE = 1;
// sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
CLOG(INFO, disass) << "Executing xRET";
check_interrupt();
return this->reg.NEXT_PC;
}
} // namespace arch
} // namespace iss
#endif /* _RISCV_HART_M_P_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,316 +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.
*
*******************************************************************************/
#ifndef _RV32GC_H_
#define _RV32GC_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct rv32gc;
template <> struct traits<rv32gc> {
constexpr static char const* const core_type = "RV32GC";
static constexpr std::array<const char*, 66> 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", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "fcsr"}};
static constexpr std::array<const char*, 66> 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", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "fcsr"}};
enum constants {XLEN=32, FLEN=64, PCLEN=32, MISA_VAL=0b1000000000101000001000100101101, PGSIZE=0x1000, PGMASK=0xfff};
constexpr static unsigned FP_REGS_SIZE = 64;
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,
F0,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
F25,
F26,
F27,
F28,
F29,
F30,
F31,
FCSR,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};
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<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 72> 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,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,32,32,32,32,32,64}};
static constexpr std::array<const uint32_t, 73> 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,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,320,328,336,344,352,360,368,376,384,392,396,400,404,408,412,416,424}};
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, CSR, FENCE, RES };
};
struct rv32gc: public arch_if {
using virt_addr_t = typename traits<rv32gc>::virt_addr_t;
using phys_addr_t = typename traits<rv32gc>::phys_addr_t;
using reg_t = typename traits<rv32gc>::reg_t;
using addr_t = typename traits<rv32gc>::addr_t;
rv32gc();
~rv32gc();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<rv32gc>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv32gc>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
struct RV32GC_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;
uint64_t F0 = 0;
uint64_t F1 = 0;
uint64_t F2 = 0;
uint64_t F3 = 0;
uint64_t F4 = 0;
uint64_t F5 = 0;
uint64_t F6 = 0;
uint64_t F7 = 0;
uint64_t F8 = 0;
uint64_t F9 = 0;
uint64_t F10 = 0;
uint64_t F11 = 0;
uint64_t F12 = 0;
uint64_t F13 = 0;
uint64_t F14 = 0;
uint64_t F15 = 0;
uint64_t F16 = 0;
uint64_t F17 = 0;
uint64_t F18 = 0;
uint64_t F19 = 0;
uint64_t F20 = 0;
uint64_t F21 = 0;
uint64_t F22 = 0;
uint64_t F23 = 0;
uint64_t F24 = 0;
uint64_t F25 = 0;
uint64_t F26 = 0;
uint64_t F27 = 0;
uint64_t F28 = 0;
uint64_t F29 = 0;
uint64_t F30 = 0;
uint64_t F31 = 0;
uint32_t FCSR = 0;
uint32_t NEXT_PC = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint32_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint32_t val){reg.FCSR = val;}
};
}
}
#endif /* _RV32GC_H_ */

View File

@ -1,250 +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.
*
*******************************************************************************/
#ifndef _RV32IMAC_H_
#define _RV32IMAC_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct rv32imac;
template <> struct traits<rv32imac> {
constexpr static char const* const core_type = "RV32IMAC";
static constexpr std::array<const char*, 33> 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"}};
static constexpr std::array<const char*, 33> 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"}};
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000101000001000100000101, PGSIZE=0x1000, PGMASK=0xfff};
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,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};
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<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 39> 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,32,32,32,32,64}};
static constexpr std::array<const uint32_t, 40> 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,140,144,148,152,160}};
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, CSR, FENCE, RES };
};
struct rv32imac: public arch_if {
using virt_addr_t = typename traits<rv32imac>::virt_addr_t;
using phys_addr_t = typename traits<rv32imac>::phys_addr_t;
using reg_t = typename traits<rv32imac>::reg_t;
using addr_t = typename traits<rv32imac>::addr_t;
rv32imac();
~rv32imac();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<rv32imac>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv32imac>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
struct RV32IMAC_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;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
};
}
}
#endif /* _RV32IMAC_H_ */

View File

@ -1,316 +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.
*
*******************************************************************************/
#ifndef _RV64GC_H_
#define _RV64GC_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct rv64gc;
template <> struct traits<rv64gc> {
constexpr static char const* const core_type = "RV64GC";
static constexpr std::array<const char*, 66> 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", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "fcsr"}};
static constexpr std::array<const char*, 66> 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", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "fcsr"}};
enum constants {XLEN=64, FLEN=64, PCLEN=64, MISA_VAL=0b1000000000101000001000100101101, PGSIZE=0x1000, PGMASK=0xfff};
constexpr static unsigned FP_REGS_SIZE = 64;
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,
F0,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
F25,
F26,
F27,
F28,
F29,
F30,
F31,
FCSR,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};
using reg_t = uint64_t;
using addr_t = uint64_t;
using code_word_t = uint64_t; //TODO: check removal
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 72> reg_bit_widths{
{64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,64,32,32,32,32,64}};
static constexpr std::array<const uint32_t, 73> reg_byte_offsets{
{0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,320,328,336,344,352,360,368,376,384,392,400,408,416,424,432,440,448,456,464,472,480,488,496,504,512,520,528,536,540,544,548,552,560}};
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, CSR, FENCE, RES };
};
struct rv64gc: public arch_if {
using virt_addr_t = typename traits<rv64gc>::virt_addr_t;
using phys_addr_t = typename traits<rv64gc>::phys_addr_t;
using reg_t = typename traits<rv64gc>::reg_t;
using addr_t = typename traits<rv64gc>::addr_t;
rv64gc();
~rv64gc();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<rv64gc>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv64gc>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
struct RV64GC_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 F0 = 0;
uint64_t F1 = 0;
uint64_t F2 = 0;
uint64_t F3 = 0;
uint64_t F4 = 0;
uint64_t F5 = 0;
uint64_t F6 = 0;
uint64_t F7 = 0;
uint64_t F8 = 0;
uint64_t F9 = 0;
uint64_t F10 = 0;
uint64_t F11 = 0;
uint64_t F12 = 0;
uint64_t F13 = 0;
uint64_t F14 = 0;
uint64_t F15 = 0;
uint64_t F16 = 0;
uint64_t F17 = 0;
uint64_t F18 = 0;
uint64_t F19 = 0;
uint64_t F20 = 0;
uint64_t F21 = 0;
uint64_t F22 = 0;
uint64_t F23 = 0;
uint64_t F24 = 0;
uint64_t F25 = 0;
uint64_t F26 = 0;
uint64_t F27 = 0;
uint64_t F28 = 0;
uint64_t F29 = 0;
uint64_t F30 = 0;
uint64_t F31 = 0;
uint32_t FCSR = 0;
uint64_t NEXT_PC = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint32_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint32_t val){reg.FCSR = val;}
};
}
}
#endif /* _RV64GC_H_ */

View File

@ -1,250 +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.
*
*******************************************************************************/
#ifndef _RV64I_H_
#define _RV64I_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct rv64i;
template <> struct traits<rv64i> {
constexpr static char const* const core_type = "RV64I";
static constexpr std::array<const char*, 33> 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"}};
static constexpr std::array<const char*, 33> 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"}};
enum constants {XLEN=64, PCLEN=64, MISA_VAL=0b10000000000001000000000100000000, PGSIZE=0x1000, PGMASK=0xfff};
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,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};
using reg_t = uint64_t;
using addr_t = uint64_t;
using code_word_t = uint64_t; //TODO: check removal
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 39> reg_bit_widths{
{64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,32,32,32,64}};
static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
{0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,256,264,272,276,280,284,288,296}};
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, CSR, FENCE, RES };
};
struct rv64i: public arch_if {
using virt_addr_t = typename traits<rv64i>::virt_addr_t;
using phys_addr_t = typename traits<rv64i>::phys_addr_t;
using reg_t = typename traits<rv64i>::reg_t;
using addr_t = typename traits<rv64i>::addr_t;
rv64i();
~rv64i();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<rv64i>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv64i>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
struct RV64I_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;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
};
}
}
#endif /* _RV64I_H_ */

282
incl/iss/arch/tgc_c.h Normal file
View File

@ -0,0 +1,282 @@
/*******************************************************************************
* 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 _TGC_C_H_
#define _TGC_C_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct tgc_c;
template <> struct traits<tgc_c> {
constexpr static char const* const core_type = "TGC_C";
static constexpr std::array<const char*, 35> 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"}};
static constexpr std::array<const char*, 35> reg_aliases{
{"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"}};
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b01000000000000000001000100000100, PGSIZE=0x1000, PGMASK=0b111111111111, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
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, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT,
CYCLE,
INSTRET
};
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<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 40> 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,64,64,64}};
static constexpr std::array<const uint32_t, 40> 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,153,161}};
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, CSR, FENCE, RES };
enum class opcode_e : unsigned short {
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,
URET = 40,
SRET = 41,
MRET = 42,
WFI = 43,
CSRRW = 44,
CSRRS = 45,
CSRRC = 46,
CSRRWI = 47,
CSRRSI = 48,
CSRRCI = 49,
MUL = 50,
MULH = 51,
MULHSU = 52,
MULHU = 53,
DIV = 54,
DIVU = 55,
REM = 56,
REMU = 57,
CADDI4SPN = 58,
CLW = 59,
CSW = 60,
CADDI = 61,
CNOP = 62,
CJAL = 63,
CLI = 64,
CLUI = 65,
CADDI16SP = 66,
__reserved_clui = 67,
CSRLI = 68,
CSRAI = 69,
CANDI = 70,
CSUB = 71,
CXOR = 72,
COR = 73,
CAND = 74,
CJ = 75,
CBEQZ = 76,
CBNEZ = 77,
CSLLI = 78,
CLWSP = 79,
CMV = 80,
CJR = 81,
__reserved_cmv = 82,
CADD = 83,
CJALR = 84,
CEBREAK = 85,
CSWSP = 86,
DII = 87,
MAX_OPCODE
};
};
struct tgc_c: public arch_if {
using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
using reg_t = typename traits<tgc_c>::reg_t;
using addr_t = typename traits<tgc_c>::addr_t;
tgc_c();
~tgc_c();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<tgc_c>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc_c>::addr_mask);
} else
return virt2phys(addr);
}
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; }
protected:
#pragma pack(push, 1)
struct TGC_C_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 trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;
#pragma pack(pop)
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
};
}
}
#endif /* _TGC_C_H_ */

View File

@ -183,43 +183,39 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
data.clear();
avail.clear();
const uint8_t *reg_base = core->get_regs_base_ptr();
for (size_t reg_no = 0; reg_no < arch::traits<ARCH>::NUM_REGS; ++reg_no) {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
auto start_reg=arch::traits<ARCH>::X0;
for (size_t reg_no = start_reg; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
for (size_t j = 0; j < reg_width; ++j) {
data.push_back(*(reg_base + offset + j));
avail.push_back(0xff);
}
// if(arch::traits<ARCH>::XLEN < 64)
// for(unsigned j=0; j<4; ++j){
// data.push_back(0);
// avail.push_back(0xff);
// }
}
// work around fill with F type registers
if (arch::traits<ARCH>::NUM_REGS < 65) {
auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
for (size_t j = 0; j < reg_width; ++j) {
data.push_back(0x0);
avail.push_back(0x00);
}
// if(arch::traits<ARCH>::XLEN < 64)
// for(unsigned j=0; j<4; ++j){
// data.push_back(0x0);
// avail.push_back(0x00);
// }
}
}
// if (arch::traits<ARCH>::NUM_REGS < 65) {
// auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
// for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
// for (size_t j = 0; j < reg_width; ++j) {
// data.push_back(0x0);
// avail.push_back(0x00);
// }
// // if(arch::traits<ARCH>::XLEN < 64)
// // for(unsigned j=0; j<4; ++j){
// // data.push_back(0x0);
// // avail.push_back(0x00);
// // }
// }
// }
return Ok;
}
template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(const std::vector<uint8_t> &data) {
auto reg_count = arch::traits<ARCH>::NUM_REGS;
auto start_reg=arch::traits<ARCH>::X0;
auto *reg_base = core->get_regs_base_ptr();
auto iter = data.data();
for (size_t reg_no = 0; reg_no < reg_count; ++reg_no) {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(iter, iter + reg_width, reg_base);
iter += 4;

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* Copyright (C) 2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,51 +30,33 @@
*
*******************************************************************************/
#include "util/ities.h"
#include <util/logging.h>
#ifndef _ISS_FACTORY_H_
#define _ISS_FACTORY_H_
#include <elfio/elfio.hpp>
#include <iss/arch/rv32gc.h>
#include <iss/iss.h>
#ifdef __cplusplus
extern "C" {
namespace iss {
using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr= std::unique_ptr<iss::vm_if>;
template<typename PLAT>
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
using core_type = typename PLAT::core;
core_type* lcpu = new PLAT();
if(backend == "interp")
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
#ifdef WITH_LLVM
if(backend == "llvm")
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#ifdef WITH_LLVM
if(backend == "tcc")
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
#endif
#include <fstream>
#include <cstdio>
#include <cstring>
using namespace iss::arch;
constexpr std::array<const char*, 66> iss::arch::traits<iss::arch::rv32gc>::reg_names;
constexpr std::array<const char*, 66> iss::arch::traits<iss::arch::rv32gc>::reg_aliases;
constexpr std::array<const uint32_t, 72> iss::arch::traits<iss::arch::rv32gc>::reg_bit_widths;
constexpr std::array<const uint32_t, 73> iss::arch::traits<iss::arch::rv32gc>::reg_byte_offsets;
rv32gc::rv32gc() {
reg.icount=0;
return {nullptr, nullptr};
}
rv32gc::~rv32gc(){
}
void rv32gc::reset(uint64_t address) {
for(size_t i=0; i<traits<rv32gc>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<rv32gc>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t* rv32gc::get_regs_base_ptr(){
return reinterpret_cast<uint8_t*>(&reg);
}
rv32gc::phys_addr_t rv32gc::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}
#endif /* _ISS_FACTORY_H_ */

View File

@ -76,7 +76,7 @@ public:
sync_type get_sync() override { return POST_SYNC; };
void callback(instr_info_t instr_info) override;
void callback(instr_info_t instr_info, exec_info const&) override;
private:
iss::instrumentation_if *arch_instr;

View File

@ -69,7 +69,7 @@ public:
sync_type get_sync() override { return POST_SYNC; };
void callback(instr_info_t instr_info) override;
void callback(instr_info_t, exec_info const&) override;
private:
Json::Value root;

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* Copyright (C) 2017-2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,33 +30,23 @@
*
*******************************************************************************/
#ifndef _SYSC_SIFIVE_FE310_H_
#define _SYSC_SIFIVE_FE310_H_
#ifndef _SYSC_CORE_COMPLEX_H_
#define _SYSC_CORE_COMPLEX_H_
#include "scc/initiator_mixin.h"
#include "scc/traceable.h"
#include "scc/utilities.h"
#include "scv4tlm/tlm_rec_initiator_socket.h"
#include <tlm/scc/initiator_mixin.h>
#include <scc/traceable.h>
#include <scc/tick2time.h>
#include <scc/utilities.h>
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
#ifdef CWR_SYSTEMC
#include <scmlinc/scml_property.h>
#else
#include <cci_configuration>
#endif
#include <tlm>
#include <tlm_core/tlm_1/tlm_req_rsp/tlm_1_interfaces/tlm_core_ifs.h>
#include <tlm_utils/tlm_quantumkeeper.h>
#include <util/range_lut.h>
class scv_tr_db;
class scv_tr_stream;
struct _scv_tr_generator_default_data;
template <class T_begin, class T_end> class scv_tr_generator;
namespace iss {
class vm_if;
namespace arch {
template <typename BASE> class riscv_hart_msu_vp;
}
namespace debugger {
class target_adapter_if;
}
}
#include <memory>
namespace sysc {
@ -70,38 +60,86 @@ public:
bool operator!=(const tlm_dmi_ext &o) const { return !operator==(o); }
};
namespace SiFive {
namespace tgfs {
class core_wrapper;
struct core_trace;
class core_complex : public sc_core::sc_module, public scc::traceable {
public:
scc::initiator_mixin<scv4tlm::tlm_rec_initiator_socket<32>> initiator;
tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
sc_core::sc_in<sc_core::sc_time> clk_i;
sc_core::sc_in<bool> rst_i{"rst_i"};
sc_core::sc_in<bool> rst_i;
sc_core::sc_in<bool> global_irq_i{"global_irq_i"};
sc_core::sc_in<bool> global_irq_i;
sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"};
sc_core::sc_in<bool> timer_irq_i;
sc_core::sc_in<bool> sw_irq_i{"sw_irq_i"};
sc_core::sc_in<bool> sw_irq_i;
sc_core::sc_vector<sc_core::sc_in<bool>> local_irq_i{"local_irq_i", 16};
sc_core::sc_vector<sc_core::sc_in<bool>> local_irq_i;
#ifndef CWR_SYSTEMC
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o;
cci::cci_param<std::string> elf_file;
cci::cci_param<std::string> elf_file{"elf_file", ""};
cci::cci_param<bool> enable_disass;
cci::cci_param<bool> enable_disass{"enable_disass", false};
cci::cci_param<uint64_t> reset_address;
cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
cci::cci_param<unsigned short> gdb_server_port;
cci::cci_param<std::string> core_type{"core_type", "tgc_c"};
cci::cci_param<bool> dump_ir;
cci::cci_param<std::string> backend{"backend", "interp"};
core_complex(sc_core::sc_module_name name);
cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0};
cci::cci_param<bool> dump_ir{"dump_ir", false};
cci::cci_param<uint32_t> mhartid{"mhartid", 0};
core_complex(sc_core::sc_module_name const& name);
#else
sc_core::sc_in<bool> clk_i{"clk_i"};
sc_core::sc_in<uint64_t> mtime_i{"mtime_i"};
scml_property<std::string> elf_file{"elf_file", ""};
scml_property<bool> enable_disass{"enable_disass", false};
scml_property<unsigned long long> reset_address{"reset_address", 0ULL};
scml_property<std::string> core_type{"core_type", "tgc_c"};
scml_property<std::string> backend{"backend", "interp"};
scml_property<unsigned> gdb_server_port{"gdb_server_port", 0};
scml_property<bool> dump_ir{"dump_ir", false};
scml_property<uint32_t> mhartid{"mhartid", 0};
core_complex(sc_core::sc_module_name const& name)
: sc_module(name)
, local_irq_i{"local_irq_i", 16}
, elf_file{"elf_file", ""}
, enable_disass{"enable_disass", false}
, reset_address{"reset_address", 0ULL}
, core_type{"core_type", "tgc_c"}
, backend{"backend", "interp"}
, gdb_server_port{"gdb_server_port", 0}
, dump_ir{"dump_ir", false}
, mhartid{"mhartid", 0}
, read_lut(tlm_dmi_ext())
, write_lut(tlm_dmi_ext())
{
init();
}
#endif
~core_complex();
@ -125,13 +163,14 @@ public:
void trace(sc_core::sc_trace_file *trf) const override;
void disass_output(uint64_t pc, const std::string instr);
bool disass_output(uint64_t pc, const std::string instr);
void set_clock_period(sc_core::sc_time period);
protected:
void before_end_of_elaboration() override;
void start_of_simulation() override;
void forward();
void run();
void clk_cb();
void rst_cb();
void sw_irq_cb();
void timer_irq_cb();
@ -140,23 +179,14 @@ protected:
util::range_lut<tlm_dmi_ext> read_lut, write_lut;
tlm_utils::tlm_quantumkeeper quantum_keeper;
std::vector<uint8_t> write_buf;
std::unique_ptr<core_wrapper> cpu;
std::unique_ptr<iss::vm_if> vm;
sc_core::sc_time curr_clk;
iss::debugger::target_adapter_if *tgt_adapter;
#ifdef WITH_SCV
//! transaction recording database
scv_tr_db *m_db;
//! blocking transaction recording stream handle
scv_tr_stream *stream_handle;
//! transaction generator handle for blocking transactions
scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data> *instr_tr_handle;
scv_tr_generator<uint64_t, _scv_tr_generator_default_data> *fetch_tr_handle;
scv_tr_handle tr_handle;
#endif
core_wrapper* cpu{nullptr};
sc_core::sc_signal<sc_core::sc_time> curr_clk;
core_trace* trc{nullptr};
std::unique_ptr<scc::tick2time> t2t;
private:
void init();
};
} /* namespace SiFive */
} /* namespace sysc */
#endif /* _SYSC_SIFIVE_FE310_H_ */
#endif /* _SYSC_CORE_COMPLEX_H_ */

View File

@ -2,31 +2,17 @@ cmake_minimum_required(VERSION 3.12)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir
# CMake useful variables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
# Set the name of your project here
project("sotfloat")
project("sotfloat" VERSION 3.0.0)
# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
set(VERSION "3e")
include(Common)
include(GNUInstallDirs)
set(SPECIALIZATION RISCV)
add_definitions(
-DSOFTFLOAT_ROUND_ODD
-DINLINE_LEVEL=5
-DSOFTFLOAT_FAST_DIV32TO16
-DSOFTFLOAT_FAST_DIV64TO32
-DSOFTFLOAT_FAST_INT64
# -DTHREAD_LOCAL=__thread
)
set(LIB_HEADERS source/include/softfloat.h source/include/softfloat_types.h)
set(PRIMITIVES
source/s_eq128.c
@ -341,32 +327,29 @@ set(OTHERS
set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS})
# Define two variables in order not to repeat ourselves.
set(LIBRARY_NAME softfloat)
# Define the library
add_library(${LIBRARY_NAME} ${LIB_SOURCES})
set_property(TARGET ${LIBRARY_NAME} PROPERTY C_STANDARD 99)
target_include_directories(${LIBRARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/build/Linux-x86_64-GCC)
target_include_directories(${LIBRARY_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/source/include ${CMAKE_CURRENT_SOURCE_DIR}/source/${SPECIALIZATION})
# Set the build version. It will be used in the name of the lib, with corresponding
# symlinks created. SOVERSION could also be specified for api version.
set_target_properties(${LIBRARY_NAME} PROPERTIES
add_library(softfloat ${LIB_SOURCES})
set_property(TARGET softfloat PROPERTY C_STANDARD 99)
target_compile_definitions(softfloat PRIVATE
SOFTFLOAT_ROUND_ODD
INLINE_LEVEL=5
SOFTFLOAT_FAST_DIV32TO16
SOFTFLOAT_FAST_DIV64TO32
SOFTFLOAT_FAST_INT64
# THREAD_LOCAL=__thread
)
target_include_directories(softfloat PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/build/Linux-x86_64-GCC)
target_include_directories(softfloat PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/source/include ${CMAKE_CURRENT_SOURCE_DIR}/source/${SPECIALIZATION})
set_target_properties(softfloat PROPERTIES
VERSION ${VERSION}
FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}"
)
# Says how and where to install software
# Targets:
# * <prefix>/lib/<libraries>
# * header location after install: <prefix>/include/<project>/*.h
# * headers can be included by C++ code `#<project>/Bar.hpp>`
install(TARGETS ${LIBRARY_NAME}
install(TARGETS softfloat
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION lib COMPONENT libs # static lib
LIBRARY DESTINATION lib COMPONENT libs # shared lib
FRAMEWORK DESTINATION bin COMPONENT libs # for mac
PUBLIC_HEADER DESTINATION include COMPONENT devel # headers for mac (note the different component -> different package)
INCLUDES DESTINATION include # headers
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel # headers for mac (note the different component -> different package)
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
)

View File

@ -49,7 +49,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
#ifdef __GNUC__
#define SOFTFLOAT_BUILTIN_CLZ 1
#define SOFTFLOAT_INTRINSIC_INT128 1
#endif
#include "opts-GCC.h"

1
src/iss/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/tgc_*.cpp

View File

@ -1,77 +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.
*
*******************************************************************************/
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/rv32imac.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::rv32imac>::reg_names;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::rv32imac>::reg_aliases;
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::rv32imac>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::rv32imac>::reg_byte_offsets;
rv32imac::rv32imac() {
reg.icount = 0;
reg.machine_state = 0x3;
}
rv32imac::~rv32imac() = default;
void rv32imac::reset(uint64_t address) {
for (size_t i = 0; i < traits<rv32imac>::NUM_REGS; ++i)
set_reg(i, std::vector<uint8_t>(sizeof(traits<rv32imac>::reg_t), 0));
reg.PC = address;
reg.NEXT_PC = reg.PC;
reg.trap_state = 0;
reg.machine_state = 0x3;
}
uint8_t *rv32imac::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(&reg); }
rv32imac::phys_addr_t rv32imac::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -1,81 +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.
*
*******************************************************************************/
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/rv64gc.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, 66> iss::arch::traits<iss::arch::rv64gc>::reg_names;
constexpr std::array<const char*, 66> iss::arch::traits<iss::arch::rv64gc>::reg_aliases;
constexpr std::array<const uint32_t, 72> iss::arch::traits<iss::arch::rv64gc>::reg_bit_widths;
constexpr std::array<const uint32_t, 73> iss::arch::traits<iss::arch::rv64gc>::reg_byte_offsets;
rv64gc::rv64gc() {
reg.icount = 0;
}
rv64gc::~rv64gc() = default;
void rv64gc::reset(uint64_t address) {
for(size_t i=0; i<traits<rv64gc>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<rv64gc>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *rv64gc::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
rv64gc::phys_addr_t rv64gc::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,51 +29,41 @@
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#include "util/ities.h"
#include <util/logging.h>
#include <elfio/elfio.hpp>
#include <iss/arch/rv64i.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <iss/arch/tgc_c.h>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::rv64i>::reg_names;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::rv64i>::reg_aliases;
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::rv64i>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::rv64i>::reg_byte_offsets;
constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_names;
constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
rv64i::rv64i() {
tgc_c::tgc_c() {
reg.icount = 0;
}
rv64i::~rv64i() = default;
tgc_c::~tgc_c() = default;
void rv64i::reset(uint64_t address) {
for(size_t i=0; i<traits<rv64i>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<rv64i>::reg_t),0));
void tgc_c::reset(uint64_t address) {
for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgc_c>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.PRIV=0x3;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *rv64i::get_regs_base_ptr() {
uint8_t *tgc_c::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
rv64i::phys_addr_t rv64i::virt2phys(const iss::addr_t &pc) {
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -31,13 +31,27 @@
*******************************************************************************/
#include <iostream>
#include <iss/iss.h>
#include <iss/factory.h>
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/arch/mnrv32.h>
#include <iss/arch/riscv_hart_m_p.h>
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif
#ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef WITH_LLVM
#include <iss/llvm/jit_helper.h>
#endif
#include <iss/log_categories.h>
#include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/instruction_count.h>
@ -63,8 +77,8 @@ int main(int argc, char *argv[]) {
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("tcc"), "the memory input file")
("isa", po::value<std::string>()->default_value("rv32gc"), "isa to use for simulation");
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
try {
@ -100,24 +114,38 @@ int main(int argc, char *argv[]) {
std::vector<iss::vm_plugin *> plugin_list;
auto res = 0;
try {
#ifdef WITH_LLVM
// application code comes here //
iss::init_jit_debug(argc, argv);
#endif
bool dump = clim.count("dump-ir");
// instantiate the simulator
std::unique_ptr<iss::vm_if> vm{nullptr};
std::unique_ptr<iss::arch_if> cpu{nullptr};
iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr};
std::string isa_opt(clim["isa"].as<std::string>());
iss::arch::mnrv32* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::mnrv32>();
if(clim["backend"].as<std::string>() == "interp")
vm = iss::interp::create(lcpu, clim["gdb-port"].as<unsigned>());
if(clim["backend"].as<std::string>() == "llvm")
vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>());
if(clim["backend"].as<std::string>() == "tcc")
vm = iss::tcc::create(lcpu, clim["gdb-port"].as<unsigned>());
cpu.reset(lcpu);
if (isa_opt == "tgc_c") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#ifdef CORE_TGC_B
if (isa_opt == "tgc_b") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D
if (isa_opt == "tgc_d") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
{
LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
return 127;
}
if (clim.count("plugin")) {
for (std::string opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name{opt_val};
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name=opt_val;
std::string filename{"cycles.txt"};
std::size_t found = opt_val.find('=');
if (found != std::string::npos) {
@ -133,7 +161,7 @@ int main(int argc, char *argv[]) {
vm->register_plugin(*ce_plugin);
plugin_list.push_back(ce_plugin);
} else {
LOG(ERROR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
return 127;
}
}
@ -150,7 +178,7 @@ int main(int argc, char *argv[]) {
}
uint64_t start_address = 0;
if (clim.count("mem"))
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::mnrv32>::MEM);
vm->get_arch()->load_file(clim["mem"].as<std::string>());
if (clim.count("elf"))
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
auto start_addr = vm->get_arch()->load_file(input);
@ -168,7 +196,7 @@ int main(int argc, char *argv[]) {
auto cycles = clim["instructions"].as<uint64_t>();
res = vm->start(cycles, dump);
} catch (std::exception &e) {
LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
<< std::endl;
res = 2;
}

View File

@ -47,10 +47,10 @@ iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
try {
is >> root;
} catch (Json::RuntimeError &e) {
LOG(ERROR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
}
} else {
LOG(ERROR) << "Could not open input file " << config_file_name;
LOG(ERR) << "Could not open input file " << config_file_name;
}
}
}
@ -77,16 +77,18 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
}
}
} else {
LOG(ERROR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
}
return true;
}
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
assert(arch_instr && "No instrumentation interface available but callback executed");
auto entry = delays[instr_info.instr_id];
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
uint32_t delay = taken ? entry.taken : entry.not_taken;
if(delay>1) arch_instr->set_curr_instr_cycles(delay);
if (taken && entry.taken > 1)
arch_instr->set_curr_instr_cycles(entry.taken);
else if (entry.not_taken > 1)
arch_instr->set_curr_instr_cycles(entry.not_taken);
}

View File

@ -46,10 +46,10 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
try {
is >> root;
} catch (Json::RuntimeError &e) {
LOG(ERROR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
}
} else {
LOG(ERROR) << "Could not open input file " << config_file_name;
LOG(ERR) << "Could not open input file " << config_file_name;
}
}
}
@ -85,11 +85,11 @@ bool iss::plugin::instruction_count::registration(const char* const version, vm_
}
rep_counts.resize(delays.size());
} else {
LOG(ERROR)<<"plugin instruction_count: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
LOG(ERR)<<"plugin instruction_count: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
}
return true;
}
void iss::plugin::instruction_count::callback(instr_info_t instr_info) {
void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
rep_counts[instr_info.instr_id]++;
}

View File

@ -30,27 +30,58 @@
*
*******************************************************************************/
// clang-format off
#include "iss/debugger/gdb_session.h"
#include "iss/debugger/encoderdecoder.h"
#include "iss/debugger/server.h"
#include "iss/debugger/target_adapter_if.h"
#include "iss/iss.h"
#include "iss/vm_types.h"
#include "sysc/core_complex.h"
#include "iss/arch/riscv_hart_msu_vp.h"
//#include "iss/arch/rv32imac.h"
#include "iss/arch/mnrv32.h"
#include "iss/debugger/encoderdecoder.h"
#include "iss/debugger/gdb_session.h"
#include "iss/debugger/server.h"
#include "iss/debugger/target_adapter_if.h"
#include "iss/iss.h"
#include "iss/vm_types.h"
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
#endif
#include "scc/report.h"
#include <sstream>
#include <iostream>
#include <sstream>
#include <array>
// clang-format on
#define STR(X) #X
#define CREATE_CORE(CN) \
if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); } else
#ifdef WITH_SCV
#include <array>
#include <scv.h>
#else
#include <scv-tr.h>
using namespace scv_tr;
#endif
#ifndef CWR_SYSTEMC
#define GET_PROP_VALUE(P) P.get_value()
#else
#define GET_PROP_VALUE(P) P.getValue()
#endif
#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 SiFive {
namespace tgfs {
using namespace std;
using namespace iss;
using namespace logging;
@ -58,72 +89,42 @@ using namespace sc_core;
namespace {
iss::debugger::encoder_decoder encdec;
}
//using core_type = iss::arch::rv32imac;
using core_type = iss::arch::mnrv32;
namespace {
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
std::array<const char*, 16> trap_str = { {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store/AMO address misaligned",
"Store/AMO access fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved",
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
"Reserved",
"Store/AMO page fault"
} };
std::array<const char*, 12> irq_str = { {
"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } };
}
class core_wrapper : public iss::arch::riscv_hart_msu_vp<core_type> {
template<typename PLAT>
class core_wrapper_t : public PLAT {
public:
using base_type = arch::riscv_hart_msu_vp<core_type>;
using phys_addr_t = typename arch::traits<core_type>::phys_addr_t;
core_wrapper(core_complex *owner)
: owner(owner)
{
}
using reg_t = typename arch::traits<typename PLAT::core>::reg_t;
using phys_addr_t = typename arch::traits<typename PLAT::core>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type;
core_wrapper_t(core_complex *owner)
: owner(owner) { }
uint32_t get_mode() { return this->reg.machine_state; }
uint32_t get_mode() { return this->reg.PRIV; }
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
inline bool get_interrupt_execution() { return this->interrupt_sim; }
base_type::hart_state<base_type::reg_t> &get_state() { return this->state; }
heart_state_t &get_state() { return this->state; }
void notify_phase(exec_phase p) override {
if (p == ISTART) owner->sync(this->reg.icount + cycle_offset);
void notify_phase(iss::arch_if::exec_phase p) override {
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
}
sync_type needed_sync() const override { return PRE_SYNC; }
void disass_output(uint64_t pc, const std::string instr) override {
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
if (!owner->disass_output(pc, instr)) {
std::stringstream s;
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
Log<Output2FILE<disass>>().get(INFO, "disass")
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 << "]";
SCCDEBUG(owner->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();
}
owner->disass_output(pc, instr);
};
status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
@ -150,6 +151,7 @@ public:
}
status read_csr(unsigned addr, reg_t &val) override {
#ifndef CWR_SYSTEMC
if((addr==arch::time || addr==arch::timeh) && owner->mtime_o.get_interface(0)){
uint64_t time_val;
bool ret = owner->mtime_o->nb_peek(time_val);
@ -160,21 +162,32 @@ public:
val = static_cast<reg_t>(time_val >> 32);
}
return ret?Ok:Err;
#else
if((addr==arch::time || addr==arch::timeh)){
uint64_t time_val = owner->mtime_i.read();
if (addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if (addr == iss::arch::timeh) {
if (sizeof(reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return Ok;
#endif
} else {
return base_type::read_csr(addr, val);
return PLAT::read_csr(addr, val);
}
}
void wait_until(uint64_t flags) override {
SCDEBUG(owner->name()) << "Sleeping until interrupt";
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
do {
wait(wfi_evt);
sc_core::wait(wfi_evt);
} while (this->reg.pending_trap == 0);
base_type::wait_until(flags);
PLAT::wait_until(flags);
}
void local_irq(short id, bool value) {
base_type::reg_t mask = 0;
reg_t mask = 0;
switch (id) {
case 16: // SW
mask = 1 << 3;
@ -195,6 +208,8 @@ public:
} else
this->csr[arch::mip] &= ~mask;
this->check_interrupt();
if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
}
private:
@ -222,7 +237,7 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func
return Err;
// no check needed as it is only called if debug server is active
tgt_adapter->add_break_condition([t]() -> unsigned {
SCTRACE() << "Checking condition at " << sc_time_stamp();
SCCTRACE() << "Checking condition at " << sc_time_stamp();
return sc_time_stamp() >= t ? std::numeric_limits<unsigned>::max() : 0;
});
return Ok;
@ -232,30 +247,95 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func
return Err;
}
core_complex::core_complex(sc_module_name name)
using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr= std::unique_ptr<iss::vm_if>;
class core_wrapper {
public:
core_wrapper(core_complex *owner) : owner(owner) { }
void reset(uint64_t addr){vm->reset(addr);}
inline void start(){vm->start();}
inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
std::function<unsigned(void)> get_mode;
std::function<uint64_t(void)> get_state;
std::function<bool(void)> get_interrupt_execution;
std::function<void(bool)> set_interrupt_execution;
std::function<void(short, bool)> local_irq;
template<typename PLAT>
std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
auto* lcpu = new core_wrapper_t<PLAT>(owner);
lcpu->set_mhartid(hart_id);
get_mode = [lcpu]() { return lcpu->get_mode(); };
get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
if(backend == "interp")
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
#ifdef WITH_LLVM
if(backend == "llvm")
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
#endif
#ifdef WITH_TCC
if(backend == "tcc")
s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
#endif
return {nullptr, nullptr};
}
void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
CREATE_CORE(tgc_c)
#ifdef CORE_TGC_B
CREATE_CORE(tgc_b)
#endif
#ifdef CORE_TGC_D
CREATE_CORE(tgc_d)
#endif
{
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
}
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
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 <time>, print_time"});
}
core_complex * const owner;
vm_ptr vm{nullptr};
cpu_ptr cpu{nullptr};
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
};
struct core_trace {
//! transaction recording database
scv_tr_db *m_db{nullptr};
//! blocking transaction recording stream handle
scv_tr_stream *stream_handle{nullptr};
//! transaction generator handle for blocking transactions
scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data> *instr_tr_handle{nullptr};
scv_tr_handle tr_handle;
};
SC_HAS_PROCESS(core_complex);// NOLINT
#ifndef CWR_SYSTEMC
core_complex::core_complex(sc_module_name const& name)
: sc_module(name)
, NAMED(initiator)
, NAMED(clk_i)
, NAMED(rst_i)
, NAMED(global_irq_i)
, NAMED(timer_irq_i)
, NAMED(local_irq_i, 16)
, NAMED(elf_file, "")
, NAMED(enable_disass, false)
, NAMED(reset_address, 0ULL)
, NAMED(gdb_server_port, 0)
, NAMED(dump_ir, false)
, read_lut(tlm_dmi_ext())
, write_lut(tlm_dmi_ext())
, tgt_adapter(nullptr)
#ifdef WITH_SCV
, m_db(scv_tr_db::get_default_db())
, stream_handle(nullptr)
, instr_tr_handle(nullptr)
, fetch_tr_handle(nullptr)
#endif
{
SC_HAS_PROCESS(core_complex);// NOLINT
init();
}
#endif
void core_complex::init(){
trc=new core_trace();
initiator.register_invalidate_direct_mem_ptr([=](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) {
@ -268,8 +348,6 @@ core_complex::core_complex(sc_module_name name)
});
SC_THREAD(run);
SC_METHOD(clk_cb);
sensitive << clk_i;
SC_METHOD(rst_cb);
sensitive << rst_i;
SC_METHOD(sw_irq_cb);
@ -278,66 +356,82 @@ core_complex::core_complex(sc_module_name name)
sensitive << timer_irq_i;
SC_METHOD(global_irq_cb);
sensitive << global_irq_i;
trc->m_db=scv_tr_db::get_default_db();
SC_METHOD(forward);
#ifndef CWR_SYSTEMC
sensitive<<clk_i;
#else
sensitive<<curr_clk;
t2t.reset(new scc::tick2time{"t2t"});
t2t->clk_i(clk_i);
t2t->clk_o(curr_clk);
#endif
}
core_complex::~core_complex() = default;
core_complex::~core_complex(){
delete cpu;
delete trc;
}
void core_complex::trace(sc_trace_file *trf) const {}
void core_complex::before_end_of_elaboration() {
cpu = scc::make_unique<core_wrapper>(this);
vm = llvm::create<core_type>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value());
#ifdef WITH_SCV
vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
#else
vm->setDisassEnabled(enable_disass.get_value());
#endif
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
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 <time>, print_time"});
SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<GET_PROP_VALUE(backend)<<" backend";
// cpu = scc::make_unique<core_wrapper>(this);
cpu = new core_wrapper(this);
cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid));
sc_assert(cpu->vm!=nullptr);
cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr);
}
void core_complex::start_of_simulation() {
quantum_keeper.reset();
if (elf_file.get_value().size() > 0) {
istringstream is(elf_file.get_value());
if (GET_PROP_VALUE(elf_file).size() > 0) {
istringstream is(GET_PROP_VALUE(elf_file));
string s;
while (getline(is, s, ',')) {
std::pair<uint64_t, bool> start_addr = cpu->load_file(s);
#ifndef CWR_SYSTEMC
if (reset_address.is_default_value() && start_addr.second == true)
reset_address.set_value(start_addr.first);
#else
if (start_addr.second == true)
reset_address=start_addr.first;
#endif
}
}
#ifdef WITH_SCV
if (m_db != nullptr && stream_handle == nullptr) {
if (trc->m_db != nullptr && trc->stream_handle == nullptr) {
string basename(this->name());
stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", m_db);
instr_tr_handle = new scv_tr_generator<>("execute", *stream_handle);
fetch_tr_handle = new scv_tr_generator<uint64_t>("fetch", *stream_handle);
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);
}
}
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[cpu->get_mode()]);
trc->tr_handle.record_attribute("MSTATUS", cpu->get_state());
trc->tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
return true;
}
void core_complex::forward() {
#ifndef CWR_SYSTEMC
set_clock_period(clk_i.read());
#else
set_clock_period(curr_clk.read());
#endif
}
void core_complex::disass_output(uint64_t pc, const std::string instr_str) {
#ifdef WITH_SCV
if (m_db == nullptr) return;
if (tr_handle.is_active()) tr_handle.end_transaction();
tr_handle = instr_tr_handle->begin_transaction();
tr_handle.record_attribute("PC", pc);
tr_handle.record_attribute("INSTR", instr_str);
tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]);
tr_handle.record_attribute("MSTATUS", cpu->get_state().mstatus.st.value);
tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
#endif
}
void core_complex::clk_cb() {
curr_clk = clk_i.read();
if (curr_clk == SC_ZERO_TIME) cpu->set_interrupt_execution(true);
void core_complex::set_clock_period(sc_core::sc_time period) {
curr_clk = period;
if (period == SC_ZERO_TIME) cpu->set_interrupt_execution(true);
}
void core_complex::rst_cb() {
@ -354,14 +448,14 @@ void core_complex::run() {
wait(SC_ZERO_TIME); // separate from elaboration phase
do {
if (rst_i.read()) {
cpu->reset(reset_address.get_value());
cpu->reset(GET_PROP_VALUE(reset_address));
wait(rst_i.negedge_event());
}
while (clk_i.read() == SC_ZERO_TIME) {
wait(clk_i.value_changed_event());
while (curr_clk.read() == SC_ZERO_TIME) {
wait(curr_clk.value_changed_event());
}
cpu->set_interrupt_execution(false);
vm->start();
cpu->start();
} while (cpu->get_interrupt_execution());
sc_stop();
}
@ -381,18 +475,16 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
gp.set_data_ptr(data);
gp.set_data_length(length);
gp.set_streaming_width(length);
sc_time delay{quantum_keeper.get_local_time()};
#ifdef WITH_SCV
if (m_db != nullptr && tr_handle.is_valid()) {
if (is_fetch && tr_handle.is_active()) {
tr_handle.end_transaction();
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 scv4tlm::tlm_recording_extension(tr_handle, this);
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
gp.set_extension(preExt);
}
#endif
initiator->b_transport(gp, delay);
SCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
SCCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
return false;
}
@ -430,16 +522,14 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
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()};
#ifdef WITH_SCV
if (m_db != nullptr && tr_handle.is_valid()) {
auto preExt = new scv4tlm::tlm_recording_extension(tr_handle, this);
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);
}
#endif
initiator->b_transport(gp, delay);
quantum_keeper.set(delay);
SCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
SCCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
return false;
}
@ -499,6 +589,5 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
return initiator->transport_dbg(gp) == length;
}
}
} /* namespace SiFive */
} /* namespace sysc */

View File

@ -32,8 +32,7 @@
// eyck@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include "fp_functions.h"
extern "C" {
#include <softfloat.h>
@ -43,71 +42,6 @@ extern "C" {
#include <limits>
namespace iss {
namespace llvm {
namespace fp_impl {
using namespace std;
using namespace ::llvm;
#define INT_TYPE(L) Type::getIntNTy(mod->getContext(), L)
#define FLOAT_TYPE Type::getFloatTy(mod->getContext())
#define DOUBLE_TYPE Type::getDoubleTy(mod->getContext())
#define VOID_TYPE Type::getVoidTy(mod->getContext())
#define THIS_PTR_TYPE Type::getIntNPtrTy(mod->getContext(), 8)
#define FDECLL(NAME, RET, ...) \
Function *NAME##_func = CurrentModule->getFunction(#NAME); \
if (!NAME##_func) { \
std::vector<Type *> NAME##_args{__VA_ARGS__}; \
FunctionType *NAME##_type = FunctionType::get(RET, NAME##_args, false); \
NAME##_func = Function::Create(NAME##_type, GlobalValue::ExternalLinkage, #NAME, CurrentModule); \
NAME##_func->setCallingConv(CallingConv::C); \
}
#define FDECL(NAME, RET, ...) \
std::vector<Type *> NAME##_args{__VA_ARGS__}; \
FunctionType *NAME##_type = FunctionType::get(RET, NAME##_args, false); \
mod->getOrInsertFunction(#NAME, NAME##_type);
void add_fp_functions_2_module(Module *mod, uint32_t flen, uint32_t xlen) {
if(flen){
FDECL(fget_flags, INT_TYPE(32));
FDECL(fadd_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsub_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fmul_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fdiv_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsqrt_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fcmp_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32));
FDECL(fcvt_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fmadd_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsel_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32));
FDECL(fclass_s, INT_TYPE(32), INT_TYPE(32));
FDECL(fcvt_32_64, INT_TYPE(64), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fcvt_64_32, INT_TYPE(32), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
if(flen>32){
FDECL(fconv_d2f, INT_TYPE(32), INT_TYPE(64), INT_TYPE(8));
FDECL(fconv_f2d, INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fadd_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fsub_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fmul_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fdiv_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fsqrt_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fcmp_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32));
FDECL(fcvt_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fmadd_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fsel_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32));
FDECL(fclass_d, INT_TYPE(64), INT_TYPE(64));
FDECL(unbox_s, INT_TYPE(32), INT_TYPE(64));
}
}
}
}
}
}
using this_t = uint8_t *;
const uint8_t rmm_map[] = {
softfloat_round_near_even /*RNE*/,

68
src/vm/fp_functions.h Normal file
View File

@ -0,0 +1,68 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020, 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.
//
// Contributors:
// eyck@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#ifndef _VM_FP_FUNCTIONS_H_
#define _VM_FP_FUNCTIONS_H_
#include <stdint.h>
extern "C" {
uint32_t fget_flags();
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fsqrt_s(uint32_t v1, uint8_t mode);
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) ;
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode);
uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op);
uint32_t fclass_s( uint32_t v1 );
uint32_t fconv_d2f(uint64_t v1, uint8_t mode);
uint64_t fconv_f2d(uint32_t v1, uint8_t mode);
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fsqrt_d(uint64_t v1, uint8_t mode);
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op);
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode);
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode);
uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op) ;
uint64_t fclass_d(uint64_t v1 );
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode);
uint32_t unbox_s(uint64_t v);
}
#endif /* RISCV_SRC_VM_FP_FUNCTIONS_H_ */

1
src/vm/interp/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/vm_tgc_*.cpp

File diff suppressed because it is too large Load Diff

4157
src/vm/interp/vm_tgc_c.cpp Normal file

File diff suppressed because it is too large Load Diff

109
src/vm/llvm/fp_impl.cpp Normal file
View File

@ -0,0 +1,109 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017, 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.
//
// Contributors:
// eyck@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
extern "C" {
#include <softfloat.h>
#include "internals.h"
#include "specialize.h"
}
#include <limits>
namespace iss {
namespace llvm {
namespace fp_impl {
using namespace std;
using namespace ::llvm;
#define INT_TYPE(L) Type::getIntNTy(mod->getContext(), L)
#define FLOAT_TYPE Type::getFloatTy(mod->getContext())
#define DOUBLE_TYPE Type::getDoubleTy(mod->getContext())
#define VOID_TYPE Type::getVoidTy(mod->getContext())
#define THIS_PTR_TYPE Type::getIntNPtrTy(mod->getContext(), 8)
#define FDECLL(NAME, RET, ...) \
Function *NAME##_func = CurrentModule->getFunction(#NAME); \
if (!NAME##_func) { \
std::vector<Type *> NAME##_args{__VA_ARGS__}; \
FunctionType *NAME##_type = FunctionType::get(RET, NAME##_args, false); \
NAME##_func = Function::Create(NAME##_type, GlobalValue::ExternalLinkage, #NAME, CurrentModule); \
NAME##_func->setCallingConv(CallingConv::C); \
}
#define FDECL(NAME, RET, ...) \
std::vector<Type *> NAME##_args{__VA_ARGS__}; \
FunctionType *NAME##_type = FunctionType::get(RET, NAME##_args, false); \
mod->getOrInsertFunction(#NAME, NAME##_type);
void add_fp_functions_2_module(Module *mod, uint32_t flen, uint32_t xlen) {
if(flen){
FDECL(fget_flags, INT_TYPE(32));
FDECL(fadd_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsub_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fmul_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fdiv_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsqrt_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fcmp_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32));
FDECL(fcvt_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fmadd_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fsel_s, INT_TYPE(32), INT_TYPE(32), INT_TYPE(32), INT_TYPE(32));
FDECL(fclass_s, INT_TYPE(32), INT_TYPE(32));
FDECL(fcvt_32_64, INT_TYPE(64), INT_TYPE(32), INT_TYPE(32), INT_TYPE(8));
FDECL(fcvt_64_32, INT_TYPE(32), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
if(flen>32){
FDECL(fconv_d2f, INT_TYPE(32), INT_TYPE(64), INT_TYPE(8));
FDECL(fconv_f2d, INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fadd_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fsub_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fmul_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fdiv_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fsqrt_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(8));
FDECL(fcmp_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32));
FDECL(fcvt_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fmadd_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32), INT_TYPE(8));
FDECL(fsel_d, INT_TYPE(64), INT_TYPE(64), INT_TYPE(64), INT_TYPE(32));
FDECL(fclass_d, INT_TYPE(64), INT_TYPE(64));
FDECL(unbox_s, INT_TYPE(32), INT_TYPE(64));
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -30,8 +30,8 @@
*
*******************************************************************************/
#include <iss/arch/mnrv32.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/arch/tgf_b.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
@ -52,7 +52,7 @@ namespace fp_impl {
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
}
namespace mnrv32 {
namespace tgf_b {
using namespace ::llvm;
using namespace iss::arch;
using namespace iss::debugger;
@ -2570,11 +2570,11 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *b
bb, this->trap_blk, 1);
}
} // namespace mnrv32
} // namespace tgf_b
template <>
std::unique_ptr<vm_if> create<arch::mnrv32>(arch::mnrv32 *core, unsigned short port, bool dump) {
auto ret = new mnrv32::vm_impl<arch::mnrv32>(*core, dump);
std::unique_ptr<vm_if> create<arch::tgf_b>(arch::tgf_b *core, unsigned short port, bool dump) {
auto ret = new tgf_b::vm_impl<arch::tgf_b>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,913 +0,0 @@
/*******************************************************************************
* Copyright (C) 2020 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.
*
*******************************************************************************/
#include <iss/arch/rv32imac.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
}
namespace tcc {
namespace rv32imac {
using namespace iss::arch;
using namespace iss::debugger;
using namespace iss::vm::llvm;
template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}
protected:
using vm_base<ARCH>::get_reg_ptr;
using this_class = vm_impl<ARCH>;
using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&);
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}
void setup_module(Module* m) override {
super::setup_module(m);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}
inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}
compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override;
void gen_leave_behavior(BasicBlock *leave_blk) override;
void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type);
void gen_trap_behavior(BasicBlock *) override;
void gen_trap_check(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
this->get_type(traits<ARCH>::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}
// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
std::array<compile_func *, 4> qlut;
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
const std::array<InstructionDesriptor, 99> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */
/* instruction JALR */
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr},
/* instruction C.ADDI4SPN */
{16, 0b0000000000000000, 0b1110000000000011, &this_class::__c_addi4spn},
/* instruction C.LW */
{16, 0b0100000000000000, 0b1110000000000011, &this_class::__c_lw},
/* instruction C.SW */
{16, 0b1100000000000000, 0b1110000000000011, &this_class::__c_sw},
/* instruction C.ADDI */
{16, 0b0000000000000001, 0b1110000000000011, &this_class::__c_addi},
/* instruction C.NOP */
{16, 0b0000000000000001, 0b1111111111111111, &this_class::__c_nop},
/* instruction C.JAL */
{16, 0b0010000000000001, 0b1110000000000011, &this_class::__c_jal},
/* instruction C.LI */
{16, 0b0100000000000001, 0b1110000000000011, &this_class::__c_li},
/* instruction C.LUI */
{16, 0b0110000000000001, 0b1110000000000011, &this_class::__c_lui},
/* instruction C.ADDI16SP */
{16, 0b0110000100000001, 0b1110111110000011, &this_class::__c_addi16sp},
/* instruction C.SRLI */
{16, 0b1000000000000001, 0b1111110000000011, &this_class::__c_srli},
/* instruction C.SRAI */
{16, 0b1000010000000001, 0b1111110000000011, &this_class::__c_srai},
/* instruction C.ANDI */
{16, 0b1000100000000001, 0b1110110000000011, &this_class::__c_andi},
/* instruction C.SUB */
{16, 0b1000110000000001, 0b1111110001100011, &this_class::__c_sub},
/* instruction C.XOR */
{16, 0b1000110000100001, 0b1111110001100011, &this_class::__c_xor},
/* instruction C.OR */
{16, 0b1000110001000001, 0b1111110001100011, &this_class::__c_or},
/* instruction C.AND */
{16, 0b1000110001100001, 0b1111110001100011, &this_class::__c_and},
/* instruction C.J */
{16, 0b1010000000000001, 0b1110000000000011, &this_class::__c_j},
/* instruction C.BEQZ */
{16, 0b1100000000000001, 0b1110000000000011, &this_class::__c_beqz},
/* instruction C.BNEZ */
{16, 0b1110000000000001, 0b1110000000000011, &this_class::__c_bnez},
/* instruction C.SLLI */
{16, 0b0000000000000010, 0b1111000000000011, &this_class::__c_slli},
/* instruction C.LWSP */
{16, 0b0100000000000010, 0b1110000000000011, &this_class::__c_lwsp},
/* instruction C.MV */
{16, 0b1000000000000010, 0b1111000000000011, &this_class::__c_mv},
/* instruction C.JR */
{16, 0b1000000000000010, 0b1111000001111111, &this_class::__c_jr},
/* instruction C.ADD */
{16, 0b1001000000000010, 0b1111000000000011, &this_class::__c_add},
/* instruction C.JALR */
{16, 0b1001000000000010, 0b1111000001111111, &this_class::__c_jalr},
/* instruction C.EBREAK */
{16, 0b1001000000000010, 0b1111111111111111, &this_class::__c_ebreak},
/* instruction C.SWSP */
{16, 0b1100000000000010, 0b1110000000000011, &this_class::__c_swsp},
/* instruction DII */
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
/* instruction LR.W */
{32, 0b00010000000000000010000000101111, 0b11111001111100000111000001111111, &this_class::__lr_w},
/* instruction SC.W */
{32, 0b00011000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__sc_w},
/* instruction AMOSWAP.W */
{32, 0b00001000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoswap_w},
/* instruction AMOADD.W */
{32, 0b00000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoadd_w},
/* instruction AMOXOR.W */
{32, 0b00100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoxor_w},
/* instruction AMOAND.W */
{32, 0b01100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoand_w},
/* instruction AMOOR.W */
{32, 0b01000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoor_w},
/* instruction AMOMIN.W */
{32, 0b10000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomin_w},
/* instruction AMOMAX.W */
{32, 0b10100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomax_w},
/* instruction AMOMINU.W */
{32, 0b11000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amominu_w},
/* instruction AMOMAXU.W */
{32, 0b11100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomaxu_w},
/* instruction MUL */
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__mul},
/* instruction MULH */
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__mulh},
/* instruction MULHSU */
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__mulhsu},
/* instruction MULHU */
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__mulhu},
/* instruction DIV */
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__div},
/* instruction DIVU */
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__divu},
/* instruction REM */
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__rem},
/* instruction REMU */
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__remu},
/* instruction LUI */
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui},
/* instruction AUIPC */
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc},
/* instruction JAL */
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal},
/* instruction BEQ */
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq},
/* instruction BNE */
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne},
/* instruction BLT */
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt},
/* instruction BGE */
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge},
/* instruction BLTU */
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu},
/* instruction BGEU */
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu},
/* instruction LB */
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb},
/* instruction LH */
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh},
/* instruction LW */
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw},
/* instruction LBU */
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu},
/* instruction LHU */
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu},
/* instruction SB */
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb},
/* instruction SH */
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh},
/* instruction SW */
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw},
/* instruction ADDI */
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi},
/* instruction SLTI */
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti},
/* instruction SLTIU */
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu},
/* instruction XORI */
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori},
/* instruction ORI */
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori},
/* instruction ANDI */
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi},
/* instruction SLLI */
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli},
/* instruction SRLI */
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli},
/* instruction SRAI */
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai},
/* instruction ADD */
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add},
/* instruction SUB */
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub},
/* instruction SLL */
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll},
/* instruction SLT */
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt},
/* instruction SLTU */
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu},
/* instruction XOR */
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor},
/* instruction SRL */
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl},
/* instruction SRA */
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra},
/* instruction OR */
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or},
/* instruction AND */
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and},
/* instruction FENCE */
{32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence},
/* instruction FENCE_I */
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i},
/* instruction ECALL */
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall},
/* instruction EBREAK */
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak},
/* instruction URET */
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret},
/* instruction SRET */
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret},
/* instruction MRET */
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret},
/* instruction WFI */
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi},
/* instruction SFENCE.VMA */
{32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma},
/* instruction CSRRW */
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw},
/* instruction CSRRS */
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs},
/* instruction CSRRC */
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc},
/* instruction CSRRWI */
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi},
/* instruction CSRRSI */
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi},
/* instruction CSRRCI */
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci},
}};
/* instruction definitions */
/* instruction 0: JALR */
compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 1: C.ADDI4SPN */
compile_ret_t __c_addi4spn(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 2: C.LW */
compile_ret_t __c_lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 3: C.SW */
compile_ret_t __c_sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 4: C.ADDI */
compile_ret_t __c_addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 5: C.NOP */
compile_ret_t __c_nop(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 6: C.JAL */
compile_ret_t __c_jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 7: C.LI */
compile_ret_t __c_li(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 8: C.LUI */
compile_ret_t __c_lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 9: C.ADDI16SP */
compile_ret_t __c_addi16sp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 10: C.SRLI */
compile_ret_t __c_srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 11: C.SRAI */
compile_ret_t __c_srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 12: C.ANDI */
compile_ret_t __c_andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 13: C.SUB */
compile_ret_t __c_sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 14: C.XOR */
compile_ret_t __c_xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 15: C.OR */
compile_ret_t __c_or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 16: C.AND */
compile_ret_t __c_and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 17: C.J */
compile_ret_t __c_j(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 18: C.BEQZ */
compile_ret_t __c_beqz(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 19: C.BNEZ */
compile_ret_t __c_bnez(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 20: C.SLLI */
compile_ret_t __c_slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 21: C.LWSP */
compile_ret_t __c_lwsp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 22: C.MV */
compile_ret_t __c_mv(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 23: C.JR */
compile_ret_t __c_jr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 24: C.ADD */
compile_ret_t __c_add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 25: C.JALR */
compile_ret_t __c_jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 26: C.EBREAK */
compile_ret_t __c_ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 27: C.SWSP */
compile_ret_t __c_swsp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 28: DII */
compile_ret_t __dii(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 29: LR.W */
compile_ret_t __lr_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 30: SC.W */
compile_ret_t __sc_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 31: AMOSWAP.W */
compile_ret_t __amoswap_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 32: AMOADD.W */
compile_ret_t __amoadd_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 33: AMOXOR.W */
compile_ret_t __amoxor_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 34: AMOAND.W */
compile_ret_t __amoand_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 35: AMOOR.W */
compile_ret_t __amoor_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 36: AMOMIN.W */
compile_ret_t __amomin_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 37: AMOMAX.W */
compile_ret_t __amomax_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 38: AMOMINU.W */
compile_ret_t __amominu_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 39: AMOMAXU.W */
compile_ret_t __amomaxu_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 40: MUL */
compile_ret_t __mul(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 41: MULH */
compile_ret_t __mulh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 42: MULHSU */
compile_ret_t __mulhsu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 43: MULHU */
compile_ret_t __mulhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 44: DIV */
compile_ret_t __div(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 45: DIVU */
compile_ret_t __divu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 46: REM */
compile_ret_t __rem(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 47: REMU */
compile_ret_t __remu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 48: LUI */
compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 49: AUIPC */
compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 50: JAL */
compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 51: BEQ */
compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 52: BNE */
compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 53: BLT */
compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 54: BGE */
compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 55: BLTU */
compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 56: BGEU */
compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 57: LB */
compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 58: LH */
compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 59: LW */
compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 60: LBU */
compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 61: LHU */
compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 62: SB */
compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 63: SH */
compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 64: SW */
compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 65: ADDI */
compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 66: SLTI */
compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 67: SLTIU */
compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 68: XORI */
compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 69: ORI */
compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 70: ANDI */
compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 71: SLLI */
compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 72: SRLI */
compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 73: SRAI */
compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 74: ADD */
compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 75: SUB */
compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 76: SLL */
compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 77: SLT */
compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 78: SLTU */
compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 79: XOR */
compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 80: SRL */
compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 81: SRA */
compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 82: OR */
compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 83: AND */
compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 84: FENCE */
compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 85: FENCE_I */
compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 86: ECALL */
compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 87: EBREAK */
compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 88: URET */
compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 89: SRET */
compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 90: MRET */
compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 91: WFI */
compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 92: SFENCE.VMA */
compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 93: CSRRW */
compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 94: CSRRS */
compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 95: CSRRC */
compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 96: CSRRWI */
compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 97: CSRRSI */
compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 98: CSRRCI */
compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) {
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true);
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits<ARCH>::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_trap_check(this->leave_blk);
return BRANCH;
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}
template <typename ARCH>
std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstrem& os) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, insn, this_block);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
}
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args);
}
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk);
auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp(
ICmpInst::ICMP_EQ, v,
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
bb, this->trap_blk, 1);
}
} // namespace rv32imac
template <>
std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, unsigned short port, bool dump) {
auto ret = new rv32imac::vm_impl<arch::rv32imac>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
}
} // namespace iss

File diff suppressed because it is too large Load Diff

View File

@ -1,724 +0,0 @@
/*******************************************************************************
* Copyright (C) 2020 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.
*
*******************************************************************************/
#include <iss/arch/rv64i.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/tcc/vm_base.h>
#include <util/logging.h>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <iss/debugger/riscv_target_adapter.h>
namespace iss {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
}
namespace tcc {
namespace rv64i {
using namespace iss::arch;
using namespace iss::debugger;
template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::tcc::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;
vm_impl();
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}
protected:
using vm_base<ARCH>::get_reg_ptr;
using this_class = vm_impl<ARCH>;
using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&);
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}
void setup_module(Module* m) override {
super::setup_module(m);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}
inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}
compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override;
void gen_leave_behavior(BasicBlock *leave_blk) override;
void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type);
void gen_trap_behavior(BasicBlock *) override;
std::string gen_trap_check(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}
inline std::string gen_set_pc(virt_addr_t pc, unsigned reg_num) {
return fmt::format("*((uint64_t*){}) = {}\n", get_reg_ptr(reg_num), next_pc_v.val);
}
// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
std::array<compile_func, LUT_SIZE> lut;
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;
std::array<compile_func *, 4> qlut;
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}
private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};
const std::array<InstructionDesriptor, 64> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */
/* instruction LUI */
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui},
/* instruction AUIPC */
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc},
/* instruction JAL */
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal},
/* instruction JALR */
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr},
/* instruction BEQ */
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq},
/* instruction BNE */
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne},
/* instruction BLT */
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt},
/* instruction BGE */
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge},
/* instruction BLTU */
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu},
/* instruction BGEU */
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu},
/* instruction LB */
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb},
/* instruction LH */
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh},
/* instruction LW */
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw},
/* instruction LBU */
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu},
/* instruction LHU */
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu},
/* instruction SB */
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb},
/* instruction SH */
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh},
/* instruction SW */
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw},
/* instruction ADDI */
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi},
/* instruction SLTI */
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti},
/* instruction SLTIU */
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu},
/* instruction XORI */
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori},
/* instruction ORI */
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori},
/* instruction ANDI */
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi},
/* instruction SLLI */
{32, 0b00000000000000000001000000010011, 0b11111100000000000111000001111111, &this_class::__slli},
/* instruction SRLI */
{32, 0b00000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srli},
/* instruction SRAI */
{32, 0b01000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srai},
/* instruction ADD */
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add},
/* instruction SUB */
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub},
/* instruction SLL */
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll},
/* instruction SLT */
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt},
/* instruction SLTU */
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu},
/* instruction XOR */
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor},
/* instruction SRL */
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl},
/* instruction SRA */
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra},
/* instruction OR */
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or},
/* instruction AND */
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and},
/* instruction FENCE */
{32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence},
/* instruction FENCE_I */
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i},
/* instruction ECALL */
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall},
/* instruction EBREAK */
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak},
/* instruction URET */
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret},
/* instruction SRET */
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret},
/* instruction MRET */
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret},
/* instruction WFI */
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi},
/* instruction SFENCE.VMA */
{32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma},
/* instruction CSRRW */
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw},
/* instruction CSRRS */
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs},
/* instruction CSRRC */
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc},
/* instruction CSRRWI */
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi},
/* instruction CSRRSI */
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi},
/* instruction CSRRCI */
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci},
/* instruction LWU */
{32, 0b00000000000000000110000000000011, 0b00000000000000000111000001111111, &this_class::__lwu},
/* instruction LD */
{32, 0b00000000000000000011000000000011, 0b00000000000000000111000001111111, &this_class::__ld},
/* instruction SD */
{32, 0b00000000000000000011000000100011, 0b00000000000000000111000001111111, &this_class::__sd},
/* instruction ADDIW */
{32, 0b00000000000000000000000000011011, 0b00000000000000000111000001111111, &this_class::__addiw},
/* instruction SLLIW */
{32, 0b00000000000000000001000000011011, 0b11111110000000000111000001111111, &this_class::__slliw},
/* instruction SRLIW */
{32, 0b00000000000000000101000000011011, 0b11111110000000000111000001111111, &this_class::__srliw},
/* instruction SRAIW */
{32, 0b01000000000000000101000000011011, 0b11111110000000000111000001111111, &this_class::__sraiw},
/* instruction ADDW */
{32, 0b00000000000000000000000000111011, 0b11111110000000000111000001111111, &this_class::__addw},
/* instruction SUBW */
{32, 0b01000000000000000000000000111011, 0b11111110000000000111000001111111, &this_class::__subw},
/* instruction SLLW */
{32, 0b00000000000000000001000000111011, 0b11111110000000000111000001111111, &this_class::__sllw},
/* instruction SRLW */
{32, 0b00000000000000000101000000111011, 0b11111110000000000111000001111111, &this_class::__srlw},
/* instruction SRAW */
{32, 0b01000000000000000101000000111011, 0b11111110000000000111000001111111, &this_class::__sraw},
}};
/* instruction definitions */
/* instruction 0: LUI */
compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 1: AUIPC */
compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
os<<fmt::format("AUIPC-{:%08x}:\n", pc.val);
os<<this->gen_sync(PRE_SYNC, 1);
uint8_t rd = ((bit_sub<7,5>(instr)));
int32_t imm = signextend<int32_t,32>((bit_sub<12,20>(instr) << 12));
if(this->disass_enabled){
/* generate console output when executing the command */
auto mnemonic = fmt::format(
"{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"),
fmt::arg("rd", name(rd)), fmt::arg("imm", imm));
this->builder.CreateCall(this->mod->getFunction("print_disass"), args);
os<<fmt::format("\tprint_disass((void*){}, {}, {});\n", this->core_ptr, pc.val, mnemonic);
}
Value* cur_pc_val = this->gen_const(64, pc.val);
pc=pc+4;
if(rd != 0){
os<<fmt::format("uint64_t res = {} + {};\n", cur_pc_val, imm);
os<<fmt::format("*((uint64_t*){}) = ret\n", get_reg_ptr(rd + traits<ARCH>::X0));
}
os<<this->gen_set_pc(pc, traits<ARCH>::NEXT_PC);
os<<this->gen_sync(POST_SYNC, 1);
os<<this->gen_trap_check(bb);
return std::make_tuple(CONT);
}
/* instruction 2: JAL */
compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 3: JALR */
compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 4: BEQ */
compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 5: BNE */
compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 6: BLT */
compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 7: BGE */
compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 8: BLTU */
compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 9: BGEU */
compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 10: LB */
compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 11: LH */
compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 12: LW */
compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 13: LBU */
compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 14: LHU */
compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 15: SB */
compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 16: SH */
compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 17: SW */
compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 18: ADDI */
compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 19: SLTI */
compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 20: SLTIU */
compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 21: XORI */
compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 22: ORI */
compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 23: ANDI */
compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 24: SLLI */
compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 25: SRLI */
compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 26: SRAI */
compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 27: ADD */
compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 28: SUB */
compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 29: SLL */
compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 30: SLT */
compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 31: SLTU */
compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 32: XOR */
compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 33: SRL */
compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 34: SRA */
compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 35: OR */
compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 36: AND */
compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 37: FENCE */
compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 38: FENCE_I */
compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 39: ECALL */
compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 40: EBREAK */
compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 41: URET */
compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 42: SRET */
compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 43: MRET */
compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 44: WFI */
compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 45: SFENCE.VMA */
compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 46: CSRRW */
compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 47: CSRRS */
compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 48: CSRRC */
compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 49: CSRRWI */
compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 50: CSRRSI */
compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 51: CSRRCI */
compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 52: LWU */
compile_ret_t __lwu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 53: LD */
compile_ret_t __ld(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 54: SD */
compile_ret_t __sd(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 55: ADDIW */
compile_ret_t __addiw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 56: SLLIW */
compile_ret_t __slliw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 57: SRLIW */
compile_ret_t __srliw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 58: SRAIW */
compile_ret_t __sraiw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 59: ADDW */
compile_ret_t __addw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 60: SUBW */
compile_ret_t __subw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 61: SLLW */
compile_ret_t __sllw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 62: SRLW */
compile_ret_t __srlw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 63: SRAW */
compile_ret_t __sraw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) {
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true);
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits<ARCH>::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_trap_check(this->leave_blk);
return BRANCH;
}
};
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}
template <typename ARCH>
std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstrem& os) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, insn, this_block);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
}
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args);
}
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk);
auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}
template <typename ARCH> inline std::string vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
return fmt::format("if(*(uint32_t){})!=0) goto trap_blk;\n", get_reg_ptr(arch::traits<ARCH>::TRAP_STATE));
}
} // namespace rv64i
template <>
std::unique_ptr<vm_if> create<arch::rv64i>(arch::rv64i *core, unsigned short port, bool dump) {
auto ret = new rv64i::vm_impl<arch::rv64i>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
}
} // namespace iss

2074
src/vm/tcc/vm_tgf_b.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff