Compare commits
125 Commits
Trace_enha
...
18e08cfc50
Author | SHA1 | Date | |
---|---|---|---|
18e08cfc50 | |||
20e920338c | |||
e151416f58 | |||
24de2bbdf5 | |||
e68f9c573f | |||
f38cc7d8b9 | |||
7af7e040da | |||
6e52af168b | |||
bd0d15f3a2 | |||
c78026b720 | |||
edba497fa1 | |||
94e46b9968 | |||
9459632f6c | |||
a0ca3cdfa5 | |||
720236ec3f | |||
957145ca84 | |||
0b719a4b57 | |||
57da07eb17 | |||
b4b03f7850 | |||
145a0cf68b | |||
1cef7de8c7 | |||
e95f422aab | |||
250ea3c980 | |||
7b31b8ca8e | |||
91a23a4a18 | |||
21d3250e1a | |||
2b094c3162 | |||
a32c83e1be | |||
7e45a25218 | |||
87b4082633 | |||
4dbc7433a5 | |||
99a9970ddd | |||
0b5de90fb1 | |||
15cd36dcd4 | |||
2281ec4144 | |||
11c481cec2 | |||
60d07f2eb6 | |||
a123beb301 | |||
ee6218279e | |||
ce5b2e60b9 | |||
c792f50427 | |||
6ed7eafc5d | |||
8a5fe58d51 | |||
16cd6d5ff5 | |||
ee2ded931d | |||
95ba5c901a | |||
32848ec396 | |||
6789cf4c32 | |||
3bc4884a9d | |||
fd6b738168 | |||
afdf8fb97f | |||
cfa7b72363 | |||
d330307ed5 | |||
916de2a26d | |||
aa70d8a54a | |||
b493745cd7 | |||
f9e8e1d857 | |||
974d64a627 | |||
d70489cbb8 | |||
d990f1cf5d | |||
1672b01e62 | |||
00b0f101ac | |||
54f75f92ea | |||
0304aac9e5 | |||
8ff55d7b92 | |||
f626ee2684 | |||
a8a2782329 | |||
98dd329833 | |||
6213445bc4 | |||
c5465bf9e2 | |||
d881cb6e63 | |||
2e4faa4d50 | |||
8e1951f298 | |||
7efa924510 | |||
febbc4fff0 | |||
39b2788b7e | |||
a943dd3bdf | |||
fedbff5971 | |||
c2758e8321 | |||
8be5fe71df | |||
3f7ce41b9d | |||
ad1cbedf00 | |||
83f54b5074 | |||
a83928fd8c | |||
ec55efd322 | |||
8c3709f92a | |||
207dbf1071 | |||
62c118e501 | |||
65dca13b42 | |||
3187cbdfe2 | |||
8c701d55c1 | |||
f585489ff5 | |||
7113683ee0 | |||
1a0fc4bd5d | |||
40d1966e9a | |||
a977200284 | |||
b20fd3eba5 | |||
b20daa1ac2 | |||
b1a18459e7 | |||
6ba7c82f80 | |||
ad7bb28b4c | |||
fa7eda0889 | |||
00e02bf565 | |||
1ad66a71d8 | |||
e60fa3d5e6 | |||
8407f6287f | |||
0833198d34 | |||
57347ae4d9 | |||
4876f18ba9 | |||
a53ee42e13 | |||
12ccfc055a | |||
feaa49d367 | |||
18f33b4a68 | |||
f096b15dbd | |||
cb5375258a | |||
076b5a39ad | |||
f40ab41899 | |||
e8fd5143bc | |||
31fb51de95 | |||
5d481eb79d | |||
1c90fe765d | |||
52ed8b81a6 | |||
0703a0a845 | |||
0c542d42aa | |||
966d1616c5 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,6 +30,5 @@ language.settings.xml
|
||||
/.gdbinit
|
||||
/*.out
|
||||
/dump.json
|
||||
/src-gen/
|
||||
/*.yaml
|
||||
/*.json
|
||||
|
1
.project
1
.project
@ -23,6 +23,5 @@
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.eclipse.linuxtools.tmf.project.nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
196
CMakeLists.txt
196
CMakeLists.txt
@ -1,87 +1,90 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
###############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
project(dbt-rise-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(flink)
|
||||
|
||||
find_package(elfio QUIET)
|
||||
find_package(Boost COMPONENTS coroutine)
|
||||
|
||||
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()
|
||||
|
||||
#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)
|
||||
find_package(jsoncpp)
|
||||
find_package(Boost COMPONENTS coroutine REQUIRED)
|
||||
|
||||
add_subdirectory(softfloat)
|
||||
|
||||
# library files
|
||||
FILE(GLOB TGC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp)
|
||||
FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
|
||||
|
||||
set(LIB_SOURCES
|
||||
src/vm/fp_functions.cpp
|
||||
src/plugin/instruction_count.cpp
|
||||
|
||||
${TGC_SOURCES}
|
||||
${TGC_VM_SOURCES}
|
||||
src/iss/arch/tgc_c.cpp
|
||||
src/vm/tcc/vm_tgc_c.cpp
|
||||
src/vm/interp/vm_tgc_c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
)
|
||||
if(TARGET RapidJSON)
|
||||
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp src/plugin/pctrace.cpp)
|
||||
if(WITH_TCC)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/tcc/vm_tgc_c.cpp
|
||||
)
|
||||
endif()
|
||||
if(WITH_LLVM)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/llvm/vm_tgc_c.cpp
|
||||
src/vm/llvm/fp_impl.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# library files
|
||||
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
|
||||
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
|
||||
foreach(FILEPATH ${GEN_ISS_SOURCES})
|
||||
get_filename_component(CORE ${FILEPATH} NAME_WE)
|
||||
string(TOUPPER ${CORE} CORE)
|
||||
list(APPEND LIB_DEFINES CORE_${CORE})
|
||||
endforeach()
|
||||
message(STATUS "Core defines are ${LIB_DEFINES}")
|
||||
|
||||
if(WITH_LLVM)
|
||||
FILE(GLOB TGC_LLVM_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/llvm/vm_*.cpp
|
||||
)
|
||||
list(APPEND LIB_SOURCES ${TGC_LLVM_SOURCES})
|
||||
FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
if(WITH_TCC)
|
||||
FILE(GLOB TGC_TCC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
|
||||
)
|
||||
list(APPEND LIB_SOURCES ${TGC_TCC_SOURCES})
|
||||
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
# 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)
|
||||
if(TARGET RapidJSON)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/iss/plugin/cycle_estimate.cpp
|
||||
src/iss/plugin/pctrace.cpp
|
||||
)
|
||||
endif()
|
||||
if(TARGET jsoncpp::jsoncpp)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/iss/plugin/instruction_count.cpp
|
||||
)
|
||||
endif()
|
||||
# Define the library
|
||||
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
|
||||
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 Boost::coroutine)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-rise-core -Wl,--no-whole-archive)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-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")
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
|
||||
|
||||
target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core)
|
||||
# only re-export the include paths
|
||||
get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL})
|
||||
get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS)
|
||||
target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)
|
||||
if(TARGET jsoncpp::jsoncpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp)
|
||||
endif()
|
||||
if(TARGET lz4::lz4)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
|
||||
@ -91,7 +94,6 @@ if(TARGET RapidJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||
endif()
|
||||
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
@ -117,18 +119,34 @@ project(tgc-sim)
|
||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||
if(TARGET ${CORE_NAME}_cpp)
|
||||
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
|
||||
else()
|
||||
FILE(GLOB TGC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
|
||||
)
|
||||
list(APPEND TGC_SOURCES ${GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
foreach(F IN LISTS TGC_SOURCES)
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
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(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
|
||||
#if(WITH_LLVM)
|
||||
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
||||
# #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
#endif()
|
||||
#if(WITH_TCC)
|
||||
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
|
||||
#endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)
|
||||
|
||||
if(TARGET Boost::program_options)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
|
||||
else()
|
||||
@ -148,27 +166,47 @@ install(TARGETS tgc-sim
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# ... CMake code to create tests ...
|
||||
add_test(NAME tgc-sim-interp
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp)
|
||||
if(WITH_TCC)
|
||||
add_test(NAME tgc-sim-tcc
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc)
|
||||
endif()
|
||||
if(WITH_LLVM)
|
||||
add_test(NAME tgc-sim-llvm
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm)
|
||||
endif()
|
||||
endif()
|
||||
###############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
||||
|
||||
include(SystemCPackage)
|
||||
if(SystemC_FOUND)
|
||||
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
|
||||
if(TARGET scc-sysc)
|
||||
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
||||
set(LIB_SOURCES
|
||||
src/sysc/core_complex.cpp
|
||||
src/sysc/register_tgc_c.cpp
|
||||
)
|
||||
FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/sysc/register_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${GEN_SC_SOURCES})
|
||||
add_library(${PROJECT_NAME} ${LIB_SOURCES})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
foreach(F IN LISTS TGC_SOURCES)
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
endif()
|
||||
endforeach()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
|
||||
# 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(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
|
537
TGC_C_instr.yaml
Normal file
537
TGC_C_instr.yaml
Normal file
@ -0,0 +1,537 @@
|
||||
|
||||
RV32I:
|
||||
- LUI:
|
||||
encoding: 0b00000000000000000000000000110111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- AUIPC:
|
||||
encoding: 0b00000000000000000000000000010111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- JAL:
|
||||
encoding: 0b00000000000000000000000001101111
|
||||
mask: 0b00000000000000000000000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: 1
|
||||
- JALR:
|
||||
encoding: 0b00000000000000000000000001100111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: 1
|
||||
- BEQ:
|
||||
encoding: 0b00000000000000000000000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BNE:
|
||||
encoding: 0b00000000000000000001000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BLT:
|
||||
encoding: 0b00000000000000000100000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BGE:
|
||||
encoding: 0b00000000000000000101000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BLTU:
|
||||
encoding: 0b00000000000000000110000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- BGEU:
|
||||
encoding: 0b00000000000000000111000001100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 32
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- LB:
|
||||
encoding: 0b00000000000000000000000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LH:
|
||||
encoding: 0b00000000000000000001000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LW:
|
||||
encoding: 0b00000000000000000010000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LBU:
|
||||
encoding: 0b00000000000000000100000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- LHU:
|
||||
encoding: 0b00000000000000000101000000000011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SB:
|
||||
encoding: 0b00000000000000000000000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SH:
|
||||
encoding: 0b00000000000000000001000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SW:
|
||||
encoding: 0b00000000000000000010000000100011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ADDI:
|
||||
encoding: 0b00000000000000000000000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTI:
|
||||
encoding: 0b00000000000000000010000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTIU:
|
||||
encoding: 0b00000000000000000011000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- XORI:
|
||||
encoding: 0b00000000000000000100000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ORI:
|
||||
encoding: 0b00000000000000000110000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ANDI:
|
||||
encoding: 0b00000000000000000111000000010011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLLI:
|
||||
encoding: 0b00000000000000000001000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRLI:
|
||||
encoding: 0b00000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRAI:
|
||||
encoding: 0b01000000000000000101000000010011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ADD:
|
||||
encoding: 0b00000000000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SUB:
|
||||
encoding: 0b01000000000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLL:
|
||||
encoding: 0b00000000000000000001000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLT:
|
||||
encoding: 0b00000000000000000010000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SLTU:
|
||||
encoding: 0b00000000000000000011000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- XOR:
|
||||
encoding: 0b00000000000000000100000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRL:
|
||||
encoding: 0b00000000000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- SRA:
|
||||
encoding: 0b01000000000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- OR:
|
||||
encoding: 0b00000000000000000110000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- AND:
|
||||
encoding: 0b00000000000000000111000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- FENCE:
|
||||
encoding: 0b00000000000000000000000000001111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- ECALL:
|
||||
encoding: 0b00000000000000000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- EBREAK:
|
||||
encoding: 0b00000000000100000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MRET:
|
||||
encoding: 0b00110000001000000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- WFI:
|
||||
encoding: 0b00010000010100000000000001110011
|
||||
mask: 0b11111111111111111111111111111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
Zicsr:
|
||||
- CSRRW:
|
||||
encoding: 0b00000000000000000001000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRS:
|
||||
encoding: 0b00000000000000000010000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRC:
|
||||
encoding: 0b00000000000000000011000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRWI:
|
||||
encoding: 0b00000000000000000101000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRSI:
|
||||
encoding: 0b00000000000000000110000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRRCI:
|
||||
encoding: 0b00000000000000000111000001110011
|
||||
mask: 0b00000000000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
Zifencei:
|
||||
- FENCE_I:
|
||||
encoding: 0b00000000000000000001000000001111
|
||||
mask: 0b00000000000000000111000001111111
|
||||
attributes: [[name:flush]]
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
RV32M:
|
||||
- MUL:
|
||||
encoding: 0b00000010000000000000000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULH:
|
||||
encoding: 0b00000010000000000001000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULHSU:
|
||||
encoding: 0b00000010000000000010000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- MULHU:
|
||||
encoding: 0b00000010000000000011000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- DIV:
|
||||
encoding: 0b00000010000000000100000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- DIVU:
|
||||
encoding: 0b00000010000000000101000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- REM:
|
||||
encoding: 0b00000010000000000110000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
- REMU:
|
||||
encoding: 0b00000010000000000111000000110011
|
||||
mask: 0b11111110000000000111000001111111
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
RV32IC:
|
||||
- CADDI4SPN:
|
||||
encoding: 0b0000000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLW:
|
||||
encoding: 0b0100000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSW:
|
||||
encoding: 0b1100000000000000
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CADDI:
|
||||
encoding: 0b0000000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CNOP:
|
||||
encoding: 0b0000000000000001
|
||||
mask: 0b1110111110000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJAL:
|
||||
encoding: 0b0010000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CLI:
|
||||
encoding: 0b0100000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLUI:
|
||||
encoding: 0b0110000000000001
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CADDI16SP:
|
||||
encoding: 0b0110000100000001
|
||||
mask: 0b1110111110000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRLI:
|
||||
encoding: 0b1000000000000001
|
||||
mask: 0b1111110000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSRAI:
|
||||
encoding: 0b1000010000000001
|
||||
mask: 0b1111110000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CANDI:
|
||||
encoding: 0b1000100000000001
|
||||
mask: 0b1110110000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSUB:
|
||||
encoding: 0b1000110000000001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CXOR:
|
||||
encoding: 0b1000110000100001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- COR:
|
||||
encoding: 0b1000110001000001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CAND:
|
||||
encoding: 0b1000110001100001
|
||||
mask: 0b1111110001100011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJ:
|
||||
encoding: 0b1010000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CBEQZ:
|
||||
encoding: 0b1100000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- CBNEZ:
|
||||
encoding: 0b1110000000000001
|
||||
mask: 0b1110000000000011
|
||||
attributes: [[name:no_cont], [name:cond]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: [1,1]
|
||||
- CSLLI:
|
||||
encoding: 0b0000000000000010
|
||||
mask: 0b1111000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CLWSP:
|
||||
encoding: 0b0100000000000010
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CMV:
|
||||
encoding: 0b1000000000000010
|
||||
mask: 0b1111000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJR:
|
||||
encoding: 0b1000000000000010
|
||||
mask: 0b1111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CADD:
|
||||
encoding: 0b1001000000000010
|
||||
mask: 0b1111000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CJALR:
|
||||
encoding: 0b1001000000000010
|
||||
mask: 0b1111000001111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: true
|
||||
delay: 1
|
||||
- CEBREAK:
|
||||
encoding: 0b1001000000000010
|
||||
mask: 0b1111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- CSWSP:
|
||||
encoding: 0b1100000000000010
|
||||
mask: 0b1110000000000011
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
- DII:
|
||||
encoding: 0b0000000000000000
|
||||
mask: 0b1111111111111111
|
||||
attributes: [[name:no_cont]]
|
||||
size: 16
|
||||
branch: false
|
||||
delay: 1
|
||||
|
35
cmake/flink.cmake
Normal file
35
cmake/flink.cmake
Normal file
@ -0,0 +1,35 @@
|
||||
# according to https://github.com/horance-liu/flink.cmake/tree/master
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
function(target_do_force_link_libraries target visibility lib)
|
||||
if(MSVC)
|
||||
target_link_libraries(${target} ${visibility} "/WHOLEARCHIVE:${lib}")
|
||||
elseif(APPLE)
|
||||
target_link_libraries(${target} ${visibility} -Wl,-force_load ${lib})
|
||||
else()
|
||||
target_link_libraries(${target} ${visibility} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(target_force_link_libraries target)
|
||||
cmake_parse_arguments(FLINK
|
||||
""
|
||||
""
|
||||
"PUBLIC;INTERFACE;PRIVATE"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
foreach(lib IN LISTS FLINK_PUBLIC)
|
||||
target_do_force_link_libraries(${target} PUBLIC ${lib})
|
||||
endforeach()
|
||||
|
||||
foreach(lib IN LISTS FLINK_INTERFACE)
|
||||
target_do_force_link_libraries(${target} INTERFACE ${lib})
|
||||
endforeach()
|
||||
|
||||
foreach(lib IN LISTS FLINK_PRIVATE)
|
||||
target_do_force_link_libraries(${target} PRIVATE ${lib})
|
||||
endforeach()
|
||||
endfunction()
|
3
contrib/.gitignore
vendored
Normal file
3
contrib/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/results
|
||||
/cwr
|
||||
/*.xml
|
43
contrib/README.md
Normal file
43
contrib/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Notes
|
||||
|
||||
* requires conan version 1.59
|
||||
* requires decent cmake version 3.23
|
||||
|
||||
Setup for tcsh:
|
||||
|
||||
```
|
||||
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
|
||||
cd TGC-ISS/
|
||||
setenv TGFS_INSTALL_ROOT `pwd`/install
|
||||
setenv COWAREHOME <your SNPS PA installation>
|
||||
setenv SNPSLMD_LICENSE_FILE <your SNPS PA license file>
|
||||
source $COWAREHOME/SLS/linux/setup.csh pae
|
||||
setenv SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM 1
|
||||
setenv PATH $COWAREHOME/common/bin/:${PATH}
|
||||
setenv CC $COWAREHOME/SLS/linux/common/bin/gcc
|
||||
setenv CXX $COWAREHOME/SLS/linux/common/bin/g++
|
||||
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
|
||||
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
|
||||
cmake --build build/PA --target install -j16
|
||||
cd dbt-rise-tgc/contrib
|
||||
# import the TGC core itself
|
||||
pct tgc_import_tb.tcl
|
||||
```
|
||||
|
||||
Setup for bash:
|
||||
|
||||
```
|
||||
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
|
||||
cd TGC-ISS/
|
||||
export TGFS_INSTALL_ROOT `pwd`/install
|
||||
module load tools/pa/T-2022.06
|
||||
export SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM=1
|
||||
export CC=$COWAREHOME/SLS/linux/common/bin/gcc
|
||||
export CXX=$COWAREHOME/SLS/linux/common/bin/g++
|
||||
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
|
||||
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
|
||||
cmake --build build/PA --target install -j16
|
||||
cd dbt-rise-tgc/contrib
|
||||
# import the TGC core itself
|
||||
pct tgc_import_tb.tcl
|
||||
```
|
@ -16,7 +16,7 @@ namespace eval Specification {
|
||||
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"]
|
||||
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc -lscc-sysc"]
|
||||
}
|
||||
default {
|
||||
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"
|
||||
|
2092
contrib/hello.dis
Normal file
2092
contrib/hello.dis
Normal file
File diff suppressed because it is too large
Load Diff
BIN
contrib/hello.elf
Executable file
BIN
contrib/hello.elf
Executable file
Binary file not shown.
BIN
contrib/minres.png
Executable file
BIN
contrib/minres.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -6,14 +6,11 @@ proc getScriptDirectory {} {
|
||||
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 encap_name sysc::tgfs::${top_design_name}
|
||||
set clocks clk_i
|
||||
set resets rst_i
|
||||
set model_prefix "i_"
|
||||
@ -28,7 +25,8 @@ set model_postfix ""
|
||||
::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
|
||||
::pct::set_import_encap_prop_as_extra_prop_flag true
|
||||
::pct::load_modules --set-category modules ${scriptDir}/tgc_import.cc
|
||||
|
||||
# Set Port Protocols correctly
|
||||
set block ${top_design_name}
|
||||
@ -38,13 +36,15 @@ foreach clock ${clocks} {
|
||||
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
|
||||
#::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_encap_build_script $block/${encap_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}
|
||||
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${encap_name} ${encap_name}()
|
||||
::pct::set_bounds i_${top_design_name} 200 300 100 400
|
||||
::pct::set_image i_${top_design_name} "$scriptDir/minres.png" center center false true
|
||||
|
||||
# export the result as component
|
||||
::pct::export_system_library ${top_design_name} ${top_design_name}.xml
|
||||
|
71
contrib/tgc_import_tb.tcl
Normal file
71
contrib/tgc_import_tb.tcl
Normal file
@ -0,0 +1,71 @@
|
||||
source tgc_import.tcl
|
||||
set hardware /HARDWARE/HW/HW
|
||||
set FW_name ${scriptDir}/hello.elf
|
||||
|
||||
puts "instantiate testbench elements"
|
||||
::paultra::add_hw_instance GenericIPlib:Memory_Generic -inst_name i_Memory_Generic
|
||||
::pct::set_param_value i_Memory_Generic/MEM:protocol {Protocol Common Parameters} address_width 30
|
||||
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/LT/clock_period_in_ns 1
|
||||
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/read/cmd_accept_cycles 1
|
||||
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/write/cmd_accept_cycles 1
|
||||
::pct::set_bounds i_Memory_Generic 1000 300 100 100
|
||||
|
||||
::paultra::add_hw_instance Bus:Bus -inst_name i_Bus
|
||||
::BLWizard::generateFramework i_Bus SBLTLM2FT * {} \
|
||||
{ common_configuration:BackBone:/advanced/num_resources_per_target:1 }
|
||||
::pct::set_bounds i_Bus 700 300 100 400
|
||||
::pct::create_connection C_ibus i_core_complex/ibus i_Bus/i_core_complex_ibus
|
||||
::pct::set_location_on_owner i_Bus/i_core_complex_ibus 10
|
||||
::pct::create_connection C_dbus i_core_complex/dbus i_Bus/i_core_complex_dbus
|
||||
::pct::set_location_on_owner i_Bus/i_core_complex_dbus 10
|
||||
::pct::create_connection C_mem i_Bus/i_Memory_Generic_MEM i_Memory_Generic/MEM
|
||||
|
||||
puts "instantiating clock manager"
|
||||
set clock "Clk"
|
||||
::hw::create_hw_instance "" GenericIPlib:ClockGenerator ${clock}_clock
|
||||
::pct::set_bounds ${clock}_clock 100 100 100 100
|
||||
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period 1000
|
||||
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period_unit sc_core::SC_PS
|
||||
|
||||
puts "instantiating reset manager"
|
||||
set reset "Rst"
|
||||
::hw::create_hw_instance "" GenericIPlib:ResetGenerator ${reset}_reset
|
||||
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time 0
|
||||
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time_unit sc_core::SC_PS
|
||||
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration 10000
|
||||
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration_unit sc_core::SC_PS
|
||||
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} active_level true
|
||||
::pct::set_bounds ${reset}_reset 300 100 100 100
|
||||
|
||||
puts "connecting reset/clock"
|
||||
::pct::create_connection C_clk . Clk_clock/CLK i_core_complex/clk_i
|
||||
::pct::add_ports_to_connection C_clk i_Bus/Clk
|
||||
::pct::add_ports_to_connection C_clk i_Memory_Generic/CLK
|
||||
::pct::create_connection C_rst . Rst_reset/RST i_core_complex/rst_i
|
||||
::pct::add_ports_to_connection C_rst i_Bus/Rst
|
||||
|
||||
puts "setting parameters for DBT-RISE-TGC/Bus and memory components"
|
||||
::pct::set_param_value $hardware/i_${top_design_name} {Extra properties} elf_file ${FW_name}
|
||||
::pct::set_address $hardware/i_${top_design_name}/ibus:i_Memory_Generic/MEM 0x0
|
||||
::pct::set_address $hardware/i_${top_design_name}/dbus:i_Memory_Generic/MEM 0x0
|
||||
::BLWizard::updateFramework i_Bus {} { common_configuration:BackBone:/advanced/num_resources_per_target:1 }
|
||||
|
||||
::pct::set_main_configuration Default {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::INFO).coloredOutput(false).logAsync(false));} {} {} {}}
|
||||
::pct::set_main_configuration Debug {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::DEBUG).coloredOutput(false).logAsync(false));} {} {} {}}
|
||||
::pct::create_simulation_build_config Debug
|
||||
::pct::set_simulation_build_project_setting Debug "Main Configuration" Default
|
||||
# add build settings and save design for next steps
|
||||
#::pct::set_simulation_build_project_setting "Debug" "Linker Flags" "-Wl,-z,muldefs $::env(VERILATOR_ROOT)/include/verilated.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_sc.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_c.cpp"
|
||||
#::pct::set_simulation_build_project_setting "Debug" "Include Paths" $::env(VERILATOR_ROOT)/include/
|
||||
|
||||
#::simulation::set_simulation_property Simulation [list run_for_duration:200ns results_dir:results/test_0 "TLM Port Trace:true"]
|
||||
#::simulation::run_simulation Simulation
|
||||
|
||||
#::pct::set_simulation_build_project_setting Debug {Export Type} {STATIC NETLIST}
|
||||
#::pct::set_simulation_build_project_setting Debug {Encapsulated Netlist} false
|
||||
#::pct::export_system "export"
|
||||
#::cd "export"
|
||||
#::scsh::open-project
|
||||
#::scsh::build
|
||||
#::scsh::elab sim
|
||||
::pct::save_system testbench.xml
|
@ -1,13 +1,13 @@
|
||||
import "RV32I.core_desc"
|
||||
import "RVM.core_desc"
|
||||
import "RVC.core_desc"
|
||||
import "ISA/RV32I.core_desc"
|
||||
import "ISA/RVM.core_desc"
|
||||
import "ISA/RVC.core_desc"
|
||||
|
||||
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000001000100000100;
|
||||
unsigned MARCHID_VAL = 0x80000003;
|
||||
unsigned int MISA_VAL = 0b01000000000000000001000100000100;
|
||||
unsigned int MARCHID_VAL = 0x80000003;
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,13 @@
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{it.size}
|
||||
regs[-1]=64 // correct for NEXT_PC
|
||||
//regs+=[32, 32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
|
||||
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||
return regs
|
||||
}
|
||||
%>
|
||||
#include "${coreDef.name.toLowerCase()}.h"
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
@ -62,15 +62,15 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
trap_state=0;
|
||||
icount=0;
|
||||
reg.trap_state=0;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
${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
|
||||
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &addr) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,12 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
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 getRegisterSizes(){
|
||||
def regs = registers.collect{nativeTypeSize(it.size)}
|
||||
// regs+=[32,32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
|
||||
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||
return regs
|
||||
}
|
||||
def getRegisterOffsets(){
|
||||
@ -57,10 +55,7 @@ def byteSize(int size){
|
||||
return 128;
|
||||
}
|
||||
def getCString(def val){
|
||||
if(val instanceof BigIntegerWithRadix)
|
||||
return ((BigIntegerWithRadix)val).toCString()
|
||||
else
|
||||
return val.toString()
|
||||
return val.toString()+'ULL'
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
@ -91,7 +86,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
||||
|
||||
enum reg_e {
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||
};
|
||||
|
||||
using reg_t = uint${addrDataWidth}_t;
|
||||
@ -116,7 +111,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
|
||||
|
||||
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
|
||||
enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %>
|
||||
${instr.instruction.name} = ${index},<%}%>
|
||||
MAX_OPCODE
|
||||
};
|
||||
@ -136,25 +131,17 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return icount; }
|
||||
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<${coreDef.name.toLowerCase()}>::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<${coreDef.name.toLowerCase()}>::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 last_branch; }
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -162,14 +149,14 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
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 instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
86
gen_input/templates/CORENAME_decoder.cpp.gtl
Normal file
86
gen_input/templates/CORENAME_decoder.cpp.gtl
Normal file
@ -0,0 +1,86 @@
|
||||
#include "${coreDef.name.toLowerCase()}.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
namespace {
|
||||
// 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
|
||||
|
||||
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_desriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e op;
|
||||
};
|
||||
|
||||
const std::array<instruction_desriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct instruction_decoder<${coreDef.name.toLowerCase()}> {
|
||||
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||
using code_word_t=traits<${coreDef.name.toLowerCase()}>::code_word_t;
|
||||
|
||||
struct instruction_pattern {
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
template<typename T>
|
||||
unsigned decode_instruction(T);
|
||||
|
||||
instruction_decoder() {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
unsigned instruction_decoder<${coreDef.name.toLowerCase()}>::decode_instruction<traits<${coreDef.name.toLowerCase()}>::code_word_t>(traits<${coreDef.name.toLowerCase()}>::code_word_t instr){
|
||||
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||
return !((instr&e.mask) ^ e.value );
|
||||
});
|
||||
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<instruction_decoder<${coreDef.name.toLowerCase()}>> traits<${coreDef.name.toLowerCase()}>::get_decoder(){
|
||||
return std::make_unique<instruction_decoder<${coreDef.name.toLowerCase()}>>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -12,5 +12,9 @@
|
||||
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
|
||||
- ${it.instruction.name}:
|
||||
encoding: ${it.encoding}
|
||||
mask: ${it.mask}<%}}%>
|
||||
mask: ${it.mask}<%if(it.attributes.size) {%>
|
||||
attributes: ${it.attributes}<%}%>
|
||||
size: ${it.length}
|
||||
branch: ${it.modifiesPC}
|
||||
delay: ${it.isConditional?"[1,1]":"1"}<%}}%>
|
||||
|
||||
|
74
gen_input/templates/CORENAME_sysc.cpp.gtl
Normal file
74
gen_input/templates/CORENAME_sysc.cpp.gtl
Normal file
@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2023 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_factory.h"
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
#include "sc_core_adapter.h"
|
||||
#include "core_complex.h"
|
||||
#include <array>
|
||||
|
||||
namespace iss {
|
||||
namespace interp {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, 2> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#if defined(WITH_TCC)
|
||||
namespace tcc {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, 2> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
@ -30,15 +30,11 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
%>
|
||||
#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>
|
||||
@ -73,6 +69,7 @@ public:
|
||||
using addr_t = typename super::addr_t;
|
||||
using reg_t = typename traits::reg_t;
|
||||
using mem_type_e = typename traits::mem_type_e;
|
||||
using opcode_e = typename traits::opcode_e;
|
||||
|
||||
vm_impl();
|
||||
|
||||
@ -92,7 +89,7 @@ protected:
|
||||
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);}
|
||||
inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
|
||||
|
||||
typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr);
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
@ -121,8 +118,8 @@ protected:
|
||||
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->core.trap_state = trap_val;
|
||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
this->core.reg.trap_state = trap_val;
|
||||
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max();
|
||||
}
|
||||
|
||||
inline void leave(unsigned lvl){
|
||||
@ -137,44 +134,6 @@ protected:
|
||||
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
|
||||
std::vector<coro_t> spawn_blocks;
|
||||
|
||||
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->core.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->core.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->core.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->core.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->core.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->core.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->core.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->core.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;
|
||||
@ -183,6 +142,7 @@ protected:
|
||||
}
|
||||
|
||||
inline void process_spawn_blocks() {
|
||||
if(spawn_blocks.size()==0) return;
|
||||
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
|
||||
if(*it){
|
||||
(*it)();
|
||||
@ -193,34 +153,101 @@ protected:
|
||||
<%functions.each{ it.eachLine { %>
|
||||
${it}<%}%>
|
||||
<%}%>
|
||||
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct InstructionDesriptor {
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
typename arch::traits<ARCH>::opcode_e op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
decoding_tree_node* root {nullptr};
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
//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;
|
||||
//}
|
||||
if(this->core.has_mmu()) {
|
||||
auto phys_pc = this->core.virt2phys(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;
|
||||
// }
|
||||
} else {
|
||||
if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok)
|
||||
return iss::Err;
|
||||
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
typename arch::traits<ARCH>::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
@ -247,16 +274,11 @@ constexpr size_t bit_count(uint32_t u) {
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
unsigned id=0;
|
||||
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);
|
||||
});
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr:instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
}
|
||||
|
||||
inline bool is_count_limit_enabled(finish_cond_e cond){
|
||||
@ -267,56 +289,48 @@ 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 arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
|
||||
for(auto& e: qlut[instr&0x3]){
|
||||
if(!((instr&e.mask) ^ e.value )) return e.id;
|
||||
}
|
||||
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||
}
|
||||
|
||||
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){
|
||||
auto pc=start;
|
||||
auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
auto& trap_state = this->core.trap_state;
|
||||
auto& icount = this->core.icount;
|
||||
auto& cycle = this->core.cycle;
|
||||
auto& instret = this->core.instret;
|
||||
auto& instr = this->core.instruction;
|
||||
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]);
|
||||
auto& trap_state = this->core.reg.trap_state;
|
||||
auto& icount = this->core.reg.icount;
|
||||
auto& cycle = this->core.reg.cycle;
|
||||
auto& instret = this->core.reg.instret;
|
||||
auto& instr = this->core.reg.instruction;
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
auto *const data = reinterpret_cast<uint8_t*>(&instr);
|
||||
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||
!(is_count_limit_enabled(cond) && icount >= icount_limit)){
|
||||
if(fetch_ins(pc, data)!=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) &&
|
||||
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto inst_id = decode_inst_id(instr);
|
||||
auto inst_id = decode_instr(root, instr);
|
||||
// pre execution stuff
|
||||
this->core.reg.last_branch = 0;
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
|
||||
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
|
||||
case arch::traits<ARCH>::opcode_e::${instr.name}: {
|
||||
<%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${nativeTypeSize(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${nativeTypeSize(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
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>TRAP_${instr.name}:break;
|
||||
}// @suppress("No break at end of case")<%}%>
|
||||
<%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${nativeTypeSize(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${nativeTypeSize(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<%instr.behavior.eachLine{%>
|
||||
${it}<%}%>
|
||||
TRAP_${instr.name}:break;
|
||||
}// @suppress("No break at end of case")<%}%>
|
||||
default: {
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
@ -325,6 +339,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
// post execution stuff
|
||||
process_spawn_blocks();
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
|
||||
// if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt
|
||||
// this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
// trap check
|
||||
if(trap_state!=0){
|
||||
super::core.enter_trap(trap_state, pc.val, instr);
|
||||
@ -335,13 +351,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
cycle++;
|
||||
pc.val=*NEXT_PC;
|
||||
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||
this->core.trap_state = this->core.pending_trap;
|
||||
this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
}
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
@ -351,3 +367,25 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
}
|
||||
} // namespace interp
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#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>
|
||||
@ -111,7 +110,7 @@ protected:
|
||||
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);
|
||||
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
|
||||
}
|
||||
|
||||
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
|
||||
@ -124,7 +123,7 @@ protected:
|
||||
// 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) };
|
||||
enum { LUT_SIZE = 1 << util::bit_count(static_cast<uint64_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint64_t>(EXTR_MASK16)) };
|
||||
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
|
||||
@ -204,10 +203,10 @@ private:
|
||||
****************************************************************************/
|
||||
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
|
||||
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
|
||||
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
|
||||
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits<ARCH>::NEXT_PC), 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->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits<ARCH>::ICOUNT), 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);
|
||||
@ -244,20 +243,21 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
// 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;
|
||||
// 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 {
|
||||
//TODO: re-add page handling
|
||||
// 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;
|
||||
@ -271,7 +271,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
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));
|
||||
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::NEXT_PC), 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) {
|
||||
@ -295,18 +295,18 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||
|
||||
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);
|
||||
auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::TRAP_STATE), 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->adj_to64(this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::PC), 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);
|
||||
auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::NEXT_PC), 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);
|
||||
auto *v = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::TRAP_STATE), 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))),
|
||||
@ -323,3 +323,25 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
}
|
||||
} // namespace llvm
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
|
||||
{
|
||||
"name" : "${instr.name}",
|
||||
"size" : ${instr.length},
|
||||
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
|
||||
}<%}%>
|
||||
]
|
||||
}
|
@ -1,223 +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 getTypeSize(size){
|
||||
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
|
||||
}
|
||||
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()
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
#define _${coreDef.name.toUpperCase()}_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct ${coreDef.name.toLowerCase()};
|
||||
|
||||
template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
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*, ${getRegisterAliasNames().size}> reg_aliases{
|
||||
{"${getRegisterAliasNames().join("\", \"")}"}};
|
||||
|
||||
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = ${coreDef.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,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT<%
|
||||
allRegs.each { reg ->
|
||||
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
|
||||
${reg.name} = ${aliasname}<%
|
||||
}
|
||||
}%>
|
||||
};
|
||||
|
||||
using reg_t = uint${regDataWidth}_t;
|
||||
|
||||
using addr_t = uint${addrDataWidth}_t;
|
||||
|
||||
using code_word_t = uint${addrDataWidth}_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, ${regSizes.size}> reg_bit_widths{
|
||||
{${regSizes.join(",")}}};
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
|
||||
{${regOffsets.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(', ')} };
|
||||
};
|
||||
|
||||
struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
|
||||
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
|
||||
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
|
||||
|
||||
${coreDef.name.toLowerCase()}();
|
||||
~${coreDef.name.toLowerCase()}();
|
||||
|
||||
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<${coreDef.name.toLowerCase()}>::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<${coreDef.name.toLowerCase()}>::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 ${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;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
<%
|
||||
def fcsr = allRegs.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;}
|
||||
<%} else { %>
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
<%}%>
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _${coreDef.name.toUpperCase()}_H_ */
|
@ -1,107 +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 <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#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*>(®);
|
||||
}
|
||||
|
||||
${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
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#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>
|
||||
@ -55,10 +54,12 @@ using namespace iss::debugger;
|
||||
|
||||
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
|
||||
public:
|
||||
using traits = arch::traits<ARCH>;
|
||||
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 mem_type_e = typename traits::mem_type_e;
|
||||
using addr_t = typename super::addr_t;
|
||||
using tu_builder = typename super::tu_builder;
|
||||
|
||||
@ -82,7 +83,7 @@ protected:
|
||||
using compile_ret_t = std::tuple<continuation_e>;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
|
||||
|
||||
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
void setup_module(std::string m) override {
|
||||
super::setup_module(m);
|
||||
@ -104,10 +105,10 @@ protected:
|
||||
|
||||
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
|
||||
switch(reg_num){
|
||||
case traits<ARCH>::NEXT_PC:
|
||||
case traits::NEXT_PC:
|
||||
tu("*next_pc = {:#x};", pc.val);
|
||||
break;
|
||||
case traits<ARCH>::PC:
|
||||
case traits::PC:
|
||||
tu("*pc = {:#x};", pc.val);
|
||||
break;
|
||||
default:
|
||||
@ -119,79 +120,59 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 {
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
decoding_tree_node* root {nullptr};
|
||||
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
||||
{${instr.length}, 0b${instr.value}, 0b${instr.mask}, &this_class::__${generator.functionName(instr.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, tu_builder& tu){<%instr.code.eachLine{%>
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||
tu("${instr.name}_{:#010x}:", pc.val);
|
||||
vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||
${it}<%}%>
|
||||
}
|
||||
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
||||
pc=pc+ ${instr.length/8};
|
||||
gen_set_pc(tu, pc, traits::NEXT_PC);
|
||||
tu.open_scope();<%instr.behavior.eachLine{%>
|
||||
${it}<%}%>
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
||||
gen_trap_check(tu);
|
||||
return returnValue;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
@ -205,11 +186,64 @@ private:
|
||||
vm_impl::gen_trap_check(tu);
|
||||
return BRANCH;
|
||||
}
|
||||
|
||||
//decoding functionality
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||
volatile CODE_WORD x = instr;
|
||||
instr = 2 * x;
|
||||
}
|
||||
|
||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
@ -217,14 +251,11 @@ 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);
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr:instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
@ -232,41 +263,40 @@ std::tuple<continuation_e>
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
|
||||
// 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;
|
||||
code_word_t instr = 0;
|
||||
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(this->core.has_mmu())
|
||||
paddr = this->core.virt2phys(pc);
|
||||
//TODO: re-add page handling
|
||||
// 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, reinterpret_cast<uint8_t*>(&instr));
|
||||
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'
|
||||
// }
|
||||
if (instr == 0x0000006f || (instr&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];
|
||||
auto f = decode_instr(root, instr);
|
||||
if (f == nullptr) {
|
||||
f = &this_class::illegal_intruction;
|
||||
}
|
||||
return (this->*f)(pc, insn, tu);
|
||||
return (this->*f)(pc, instr, tu);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
@ -274,12 +304,12 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
} // namespace mnrv32
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
@ -287,5 +317,27 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||
return std::unique_ptr<vm_if>(ret);
|
||||
}
|
||||
}
|
||||
} // namesapce tcc
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
|
||||
{
|
||||
"name" : "${instr.name}",
|
||||
"size" : ${instr.length},
|
||||
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
|
||||
}<%}%>
|
||||
]
|
||||
}
|
@ -1,223 +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 getTypeSize(size){
|
||||
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
|
||||
}
|
||||
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()
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
#define _${coreDef.name.toUpperCase()}_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct ${coreDef.name.toLowerCase()};
|
||||
|
||||
template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
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*, ${getRegisterAliasNames().size}> reg_aliases{
|
||||
{"${getRegisterAliasNames().join("\", \"")}"}};
|
||||
|
||||
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = ${coreDef.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,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT<%
|
||||
allRegs.each { reg ->
|
||||
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
|
||||
${reg.name} = ${aliasname}<%
|
||||
}
|
||||
}%>
|
||||
};
|
||||
|
||||
using reg_t = uint${regDataWidth}_t;
|
||||
|
||||
using addr_t = uint${addrDataWidth}_t;
|
||||
|
||||
using code_word_t = uint${addrDataWidth}_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, ${regSizes.size}> reg_bit_widths{
|
||||
{${regSizes.join(",")}}};
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
|
||||
{${regOffsets.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(', ')} };
|
||||
};
|
||||
|
||||
struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
|
||||
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
|
||||
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
|
||||
|
||||
${coreDef.name.toLowerCase()}();
|
||||
~${coreDef.name.toLowerCase()}();
|
||||
|
||||
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<${coreDef.name.toLowerCase()}>::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<${coreDef.name.toLowerCase()}>::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 ${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;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
<%
|
||||
def fcsr = allRegs.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;}
|
||||
<%} else { %>
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
<%}%>
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _${coreDef.name.toUpperCase()}_H_ */
|
@ -1,107 +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 <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#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*>(®);
|
||||
}
|
||||
|
||||
${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
|
||||
}
|
||||
|
1
incl/iss/arch/.gitignore
vendored
1
incl/iss/arch/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/tgc_*.h
|
@ -8,7 +8,7 @@ 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(Common)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(SPECIALIZATION RISCV)
|
||||
|
3
src-gen/.gitignore
vendored
Normal file
3
src-gen/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/iss
|
||||
/vm
|
||||
/sysc
|
@ -51,12 +51,18 @@ enum riscv_csr {
|
||||
ustatus = 0x000,
|
||||
uie = 0x004,
|
||||
utvec = 0x005,
|
||||
utvt = 0x007, //CLIC
|
||||
// User Trap Handling
|
||||
uscratch = 0x040,
|
||||
uepc = 0x041,
|
||||
ucause = 0x042,
|
||||
utval = 0x043,
|
||||
uip = 0x044,
|
||||
uxnti = 0x045, //CLIC
|
||||
uintstatus = 0xCB1, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||
uintthresh = 0x047, // MRW Interrupt-level threshold (CLIC) - addr subject to change
|
||||
uscratchcsw = 0x048, // MRW Conditional scratch swap on priv mode change (CLIC)
|
||||
uscratchcswl = 0x049, // MRW Conditional scratch swap on level change (CLIC)
|
||||
// User Floating-Point CSRs
|
||||
fflags = 0x001,
|
||||
frm = 0x002,
|
||||
@ -114,11 +120,10 @@ enum riscv_csr {
|
||||
mtval = 0x343,
|
||||
mip = 0x344,
|
||||
mxnti = 0x345, //CLIC
|
||||
mintstatus = 0x346, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||
mintstatus = 0xFB1, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||
mintthresh = 0x347, // MRW Interrupt-level threshold (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,
|
||||
@ -216,6 +221,7 @@ struct vm_info {
|
||||
|
||||
struct feature_config {
|
||||
uint64_t clic_base{0xc0000000};
|
||||
unsigned clic_int_ctl_bits{4};
|
||||
unsigned clic_num_irq{16};
|
||||
unsigned clic_num_trigger{0};
|
||||
uint64_t tcm_base{0x10000000};
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* Copyright (C) 2019 - 2023 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -172,17 +172,94 @@ public:
|
||||
return 0b00000000000000000001100010001000;
|
||||
}
|
||||
};
|
||||
|
||||
// specialization 64bit
|
||||
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint64_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, 63, 1);
|
||||
// value of XLEN for S-mode
|
||||
BF_FIELD(SXL, 34, 2);
|
||||
// value of XLEN for U-mode
|
||||
BF_FIELD(UXL, 32, 2);
|
||||
// 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 T get_mask() {
|
||||
//return 0x8000000f007ff9ddULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011
|
||||
//
|
||||
// +-TSR
|
||||
// |+-TW
|
||||
// ||+-TVM
|
||||
// |||+-MXR
|
||||
// ||||+-SUM
|
||||
// |||||+-MPRV
|
||||
// |||||| +-XS
|
||||
// |||||| | +-FS
|
||||
// |||||| | | +-MPP
|
||||
// |||||| | | | +-SPP
|
||||
// |||||| | | | |+-MPIE
|
||||
// ||||||/|/|/| || +-MIE
|
||||
return 0b00000000000000000001100010001000;
|
||||
}
|
||||
};
|
||||
|
||||
using hart_state_type = hart_state<reg_t>;
|
||||
|
||||
constexpr reg_t get_irq_mask() {
|
||||
return 0b100010001000; // only machine mode is supported
|
||||
}
|
||||
|
||||
constexpr bool has_compressed() {
|
||||
return traits<BASE>::MISA_VAL&0b0100;
|
||||
}
|
||||
constexpr reg_t get_pc_mask() {
|
||||
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
|
||||
return has_compressed()?(reg_t)~1:(reg_t)~3;
|
||||
}
|
||||
|
||||
riscv_hart_m_p();
|
||||
riscv_hart_m_p(feature_config cfg = feature_config{});
|
||||
virtual ~riscv_hart_m_p() = default;
|
||||
|
||||
void reset(uint64_t address) override;
|
||||
@ -194,28 +271,20 @@ public:
|
||||
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;
|
||||
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
|
||||
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
||||
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->icount + cycle_offset);
|
||||
pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@ -239,15 +308,17 @@ protected:
|
||||
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
uint64_t get_instr_count() override { return arch.icount; }
|
||||
uint64_t get_instr_count() override { return arch.reg.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
void set_curr_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
|
||||
riscv_hart_m_p<BASE, FEAT> &arch;
|
||||
};
|
||||
@ -285,7 +356,6 @@ protected:
|
||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
|
||||
uint8_t clic_cfg_reg{0};
|
||||
uint32_t clic_info_reg{0};
|
||||
std::array<uint32_t, 32> clic_inttrig_reg;
|
||||
union clic_int_reg_t {
|
||||
struct{
|
||||
@ -297,6 +367,8 @@ protected:
|
||||
uint32_t raw;
|
||||
};
|
||||
std::vector<clic_int_reg_t> clic_int_reg;
|
||||
uint8_t clic_mprev_lvl{0};
|
||||
uint8_t clic_mact_lvl{0};
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
@ -312,14 +384,16 @@ protected:
|
||||
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 read_cause(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 read_hartid(unsigned addr, reg_t &val);
|
||||
iss::status write_epc(unsigned addr, reg_t val);
|
||||
iss::status write_intstatus(unsigned addr, reg_t val);
|
||||
iss::status read_intstatus(unsigned addr, reg_t& val);
|
||||
iss::status write_intthresh(unsigned addr, reg_t val);
|
||||
iss::status write_xtvt(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_dcsr_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
||||
@ -337,8 +411,6 @@ protected:
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void check_interrupt();
|
||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
||||
@ -346,30 +418,37 @@ protected:
|
||||
std::vector<std::function<mem_read_f>> memfn_read;
|
||||
std::vector<std::function<mem_write_f>> memfn_write;
|
||||
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
|
||||
uint64_t clic_base_addr{0};
|
||||
unsigned clic_num_irq{0};
|
||||
unsigned clic_num_trigger{0};
|
||||
unsigned mcause_max_irq{16};
|
||||
feature_config cfg;
|
||||
uint64_t mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||
std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
|
||||
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
|
||||
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
|
||||
hart_mem_rd_delegate = rd;
|
||||
hart_mem_wr_delegate = wr;
|
||||
return ret;
|
||||
}
|
||||
std::function<mem_read_f> hart_mem_rd_delegate;
|
||||
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
: state()
|
||||
, instr_if(*this) {
|
||||
, instr_if(*this)
|
||||
, cfg(cfg) {
|
||||
// reset values
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
csr[mvendorid] = 0x669;
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file
|
||||
|
||||
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_csr_reg;
|
||||
}
|
||||
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||
if(traits<BASE>::XLEN==32) for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
@ -380,34 +459,40 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
}
|
||||
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
||||
if(traits<BASE>::XLEN==32) for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
//csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// common regs
|
||||
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
|
||||
for(auto addr: addrs) {
|
||||
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
|
||||
for(auto addr: roaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_null;
|
||||
}
|
||||
const std::array<unsigned, 4> rwaddrs{{mepc, mtvec, mscratch, mtval}};
|
||||
for(auto addr: rwaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// special handling & overrides
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
csr_rd_cb[timeh] = &this_class::read_time;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[timeh] = &this_class::read_time;
|
||||
csr_rd_cb[cycle] = &this_class::read_cycle;
|
||||
csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
csr_rd_cb[instret] = &this_class::read_instret;
|
||||
csr_rd_cb[instreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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_rd_cb[mcause] = &this_class::read_cause;
|
||||
csr_wr_cb[mcause] = &this_class::write_cause;
|
||||
csr_rd_cb[mtvec] = &this_class::read_tvec;
|
||||
csr_wr_cb[mepc] = &this_class::write_epc;
|
||||
@ -422,43 +507,38 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||
csr_wr_cb[mimpid] = &this_class::write_null;
|
||||
if(FEAT & FEAT_CLIC) {
|
||||
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mtvt] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintstatus] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mtvt] = &this_class::write_xtvt;
|
||||
// csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintstatus] = &this_class::read_intstatus;
|
||||
csr_wr_cb[mintstatus] = &this_class::write_null;
|
||||
csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||
// csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||
// csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
|
||||
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mclicbase] = &this_class::write_null;
|
||||
|
||||
clic_base_addr=0xC0000000;
|
||||
clic_num_irq=16;
|
||||
clic_int_reg.resize(clic_num_irq);
|
||||
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw=0});
|
||||
clic_cfg_reg=0x20;
|
||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
|
||||
mcause_max_irq=clic_num_irq+16;
|
||||
insert_mem_range(clic_base_addr, 0x5000UL,
|
||||
clic_mact_lvl = clic_mprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
csr[mintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
insert_mem_range(cfg.clic_base, 0x5000UL,
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
|
||||
}
|
||||
if(FEAT & FEAT_TCM) {
|
||||
tcm.resize(0x8000);
|
||||
tcm.resize(cfg.tcm_size);
|
||||
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
|
||||
auto offset=addr.val-0x10000000;
|
||||
auto offset=addr.val-this->cfg.tcm_base;
|
||||
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
|
||||
return iss::Ok;
|
||||
};
|
||||
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
|
||||
auto offset=addr.val-0x10000000;
|
||||
auto offset=addr.val-this->cfg.tcm_base;
|
||||
std::copy(data, data + length, tcm.data() + offset);
|
||||
return iss::Ok;
|
||||
};
|
||||
insert_mem_range(0x10000000, 0x8000UL, read_clic_cb, write_clic_cb);
|
||||
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
|
||||
}
|
||||
if(FEAT & FEAT_DEBUG){
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||
@ -470,6 +550,12 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
||||
}
|
||||
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status {
|
||||
return this->read_mem(a, l, d);
|
||||
};
|
||||
hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status {
|
||||
return this->write_mem(a, l, d);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||
@ -477,10 +563,10 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
if (fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(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
|
||||
@ -533,9 +619,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
@ -567,22 +653,22 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
try {
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
auto alignment = is_fetch(access)? (has_compressed()? 2 : 4) : length;
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1UL << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
this->reg.trap_state = (1UL << 31) | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
@ -590,17 +676,17 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_read[idx](phys_addr, length, data);
|
||||
} else
|
||||
res = read_mem( phys_addr, length, data);
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
} else {
|
||||
res = read_mem( phys_addr, length, data);
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -626,7 +712,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -664,16 +750,16 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
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->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1UL << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||
this->trap_state = 1<<31 | 6<<16;
|
||||
this->reg.trap_state = (1UL << 31) | 6<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
@ -688,19 +774,18 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 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) {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
switch (addr) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
@ -712,16 +797,16 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
}
|
||||
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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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
|
||||
@ -753,7 +838,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -799,11 +884,10 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
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;
|
||||
@ -811,8 +895,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::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) {
|
||||
@ -821,38 +903,35 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
val = static_cast<reg_t>(this->instret);
|
||||
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->instret >> 32);
|
||||
val = static_cast<reg_t>(this->reg.instret >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
if ((addr&0xff) == (minstreth&0xff))
|
||||
return iss::Err;
|
||||
this->instret = static_cast<uint64_t>(val);
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
this->instret = (this->instret & 0xffffffff00000000) + val;
|
||||
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
|
||||
} else {
|
||||
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
|
||||
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
|
||||
}
|
||||
}
|
||||
this->instret--;
|
||||
this->reg.instret--;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
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) {
|
||||
@ -863,7 +942,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) {
|
||||
val = csr[mtvec] & ~2;
|
||||
val = FEAT & features_e::FEAT_CLIC? csr[addr] : csr[addr] & ~2;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -878,8 +957,28 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||
val |= clic_mprev_lvl<<16;
|
||||
val |= state.mstatus.MPIE<<27;
|
||||
val |= state.mstatus.MPP<<28;
|
||||
} else
|
||||
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))| (mcause_max_irq-1));
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||
clic_mprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
|
||||
state.mstatus.MPIE=(val>>27)&0x1;
|
||||
state.mstatus.MPP=(val>>28)&0x3;
|
||||
} else {
|
||||
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -951,28 +1050,27 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||
val = (clic_mact_lvl&0xff) <<24;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
|
||||
csr[addr]= val &0xff;
|
||||
csr[addr]= (val &0xff) | (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||
csr[addr]= val & ~0x3fULL;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::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->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
|
||||
@ -984,32 +1082,14 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::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];
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||
uart_buf.str("");
|
||||
}
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
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));
|
||||
@ -1031,7 +1111,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1062,15 +1142,13 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
*data=clic_cfg_reg;
|
||||
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
|
||||
read_reg_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
} else {
|
||||
@ -1081,17 +1159,15 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
clic_cfg_reg = *data;
|
||||
clic_cfg_reg&= 0x7e;
|
||||
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
|
||||
// write_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
clic_cfg_reg = (clic_cfg_reg&~0x1e) | (*data&0x1e);
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
clic_int_reg[offset].raw &= 0xf0c70101; // clicIntCtlBits->0xf0, clicintattr->0xc7, clicintie->0x1, clicintip->0x1
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
@ -1102,6 +1178,7 @@ template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
|
||||
//TODO: Implement CLIC functionality
|
||||
//auto ideleg = csr[mideleg];
|
||||
// Multiple simultaneous interrupts and traps at the same privilege level are
|
||||
// handled in the following decreasing priority order:
|
||||
@ -1109,8 +1186,8 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
||||
// 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);
|
||||
bool mstatus_mie = state.mstatus.MIE;
|
||||
auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie;
|
||||
auto enabled_interrupts = m_enabled ? ena_irq : 0;
|
||||
|
||||
if (enabled_interrupts != 0) {
|
||||
@ -1119,14 +1196,14 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::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 const trap_id = bit_sub<0, 16>(flags);
|
||||
auto cause = bit_sub<16, 15>(flags);
|
||||
// calculate effective privilege level
|
||||
unsigned new_priv = PRIV_M;
|
||||
@ -1146,7 +1223,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
csr[mtval] = static_cast<reg_t>(addr);
|
||||
break;
|
||||
case 2:
|
||||
csr[mtval] = (instr & 0x3)==3?instr:instr&0xffff;
|
||||
csr[mtval] = (!has_compressed() || (instr & 0x3)==3)?instr:instr&0xffff;
|
||||
break;
|
||||
case 3:
|
||||
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||
@ -1167,7 +1244,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
fault_data = 0;
|
||||
} else {
|
||||
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
||||
this->pending_trap = 0;
|
||||
this->reg.pending_trap = 0;
|
||||
}
|
||||
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||
// update mstatus
|
||||
@ -1182,14 +1259,22 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
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;
|
||||
auto xtvec = csr[mtvec];
|
||||
// calculate adds// set NEXT_PC to trap addressess to jump to based on MODE
|
||||
if((FEAT & features_e::FEAT_CLIC) && trap_id!=0 && (xtvec & 0x3UL)==3UL) {
|
||||
reg_t data;
|
||||
auto ret = read(address_type::LOGICAL, access_type::READ, 0, csr[mtvt], sizeof(reg_t), reinterpret_cast<uint8_t*>(&data));
|
||||
if(ret == iss::Err)
|
||||
return this->reg.PC;
|
||||
this->reg.NEXT_PC = data;
|
||||
} else {
|
||||
// bits in mtvec
|
||||
this->reg.NEXT_PC = xtvec & ~0x3UL;
|
||||
if ((xtvec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||
}
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->trap_state = 0;
|
||||
this->reg.trap_state = 0;
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
@ -1210,6 +1295,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::l
|
||||
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
|
||||
CLOG(INFO, disass) << "Executing xRET";
|
||||
check_interrupt();
|
||||
this->reg.trap_state = this->reg.pending_trap;
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -307,23 +307,18 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void set_irq_num(unsigned i) {
|
||||
mcause_max_irq=1<<util::ilog2(i);
|
||||
}
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
@ -336,19 +331,21 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
virtual uint64_t get_pc() { return arch.get_pc(); };
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
|
||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
uint64_t get_instr_count() { return arch.icount; }
|
||||
uint64_t get_instr_count() override { return arch.reg.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
|
||||
riscv_hart_msu_vp<BASE> &arch;
|
||||
};
|
||||
@ -387,16 +384,17 @@ protected:
|
||||
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);
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_csr_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_mtvec(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);
|
||||
@ -404,6 +402,8 @@ private:
|
||||
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_ideleg(unsigned addr, reg_t val);
|
||||
iss::status write_edeleg(unsigned addr, reg_t val);
|
||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
iss::status write_epc(unsigned addr, reg_t val);
|
||||
iss::status read_satp(unsigned addr, reg_t &val);
|
||||
@ -422,10 +422,7 @@ private:
|
||||
}
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
@ -433,6 +430,7 @@ template <typename BASE>
|
||||
riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
: state()
|
||||
, instr_if(*this) {
|
||||
this->_has_mmu = true;
|
||||
// reset values
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
csr[mvendorid] = 0x669;
|
||||
@ -442,22 +440,22 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
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;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
}
|
||||
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
//csr_wr_cb[addr] = &this_class::write_reg;
|
||||
//csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// common regs
|
||||
const std::array<unsigned, 22> addrs{{
|
||||
@ -467,25 +465,25 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
uepc, utvec, uscratch, ucause, utval, uscratch
|
||||
}};
|
||||
for(auto addr: addrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_reg;
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// special handling & overrides
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
csr_rd_cb[timeh] = &this_class::read_time;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[timeh] = &this_class::read_time;
|
||||
csr_rd_cb[cycle] = &this_class::read_cycle;
|
||||
csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
csr_rd_cb[instret] = &this_class::read_instret;
|
||||
csr_rd_cb[instreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
@ -535,10 +533,10 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
|
||||
if (fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(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
|
||||
@ -557,7 +555,7 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
|
||||
traits<BASE>::MEM, pseg->get_physical_address(),
|
||||
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
|
||||
if (res != iss::Ok)
|
||||
LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex
|
||||
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex
|
||||
<< pseg->get_physical_address();
|
||||
}
|
||||
}
|
||||
@ -591,9 +589,9 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template <typename BASE>
|
||||
@ -615,12 +613,12 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
this->reg.trap_state = 1<<31 | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -635,16 +633,14 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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);
|
||||
auto res = read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -660,7 +656,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
case 3: { // SFENCE:VMA upper
|
||||
auto tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -681,7 +677,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -719,9 +715,10 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
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->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
try {
|
||||
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
|
||||
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
|
||||
@ -734,21 +731,18 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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);
|
||||
auto res = write_mem(paddr, length, data);
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 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
|
||||
@ -792,7 +786,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
ptw.clear();
|
||||
auto tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -808,7 +802,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -853,8 +847,8 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<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) {
|
||||
@ -864,10 +858,8 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<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) {
|
||||
@ -876,24 +868,21 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
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) {
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<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) {
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<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)) {
|
||||
@ -906,8 +895,8 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne
|
||||
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->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<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) {
|
||||
@ -917,7 +906,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
||||
val = csr[addr] & ~2;
|
||||
return iss::Ok;
|
||||
}
|
||||
@ -976,7 +965,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
|
||||
reg_t tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -987,7 +976,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) {
|
||||
reg_t tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -1031,20 +1020,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigne
|
||||
|
||||
template <typename BASE>
|
||||
iss::status riscv_hart_msu_vp<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->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
|
||||
@ -1056,32 +1032,14 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
|
||||
|
||||
template <typename BASE>
|
||||
iss::status riscv_hart_msu_vp<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];
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||
uart_buf.str("");
|
||||
}
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
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));
|
||||
@ -1103,7 +1061,7 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1172,7 +1130,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
||||
if (enabled_interrupts != 0) {
|
||||
int res = 0;
|
||||
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -1273,6 +1231,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
auto cur_priv = this->reg.PRIV;
|
||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||
// calculate and write mcause val
|
||||
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state;
|
||||
auto trap_id = bit_sub<0, 16>(flags);
|
||||
auto cause = bit_sub<16, 15>(flags);
|
||||
if (trap_id == 0 && cause == 11) cause = 0x8 + cur_priv; // adjust environment call cause
|
||||
@ -1316,7 +1275,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
|
||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||
this->pending_trap = 0;
|
||||
this->reg.pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << 31) + cause;
|
||||
@ -1361,7 +1320,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
<< lvl[cur_priv] << " to " << lvl[new_priv];
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->trap_state = 0;
|
||||
this->reg.trap_state = 0;
|
||||
update_vm_info();
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
@ -1373,7 +1332,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f
|
||||
|
||||
auto tsr = state.mstatus.TSR;
|
||||
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return this->reg.PC;
|
||||
}
|
||||
@ -1412,7 +1371,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::wait_until(uint64_t flags
|
||||
auto status = state.mstatus;
|
||||
auto tw = status.TW;
|
||||
if (this->reg.PRIV == PRIV_S && tw != 0) {
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -181,6 +181,89 @@ public:
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// specialization 64bit
|
||||
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint64_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, 63, 1);
|
||||
// value of XLEN for S-mode
|
||||
BF_FIELD(SXL, 34, 2);
|
||||
// value of XLEN for U-mode
|
||||
BF_FIELD(UXL, 32, 2);
|
||||
// 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, unsigned priv_lvl) {
|
||||
auto mask = get_mask(priv_lvl);
|
||||
auto new_val = (mstatus.backing.val & ~mask) | (val & mask);
|
||||
mstatus = new_val;
|
||||
}
|
||||
|
||||
static constexpr uint64_t get_mask(unsigned priv_lvl) {
|
||||
#if __cplusplus < 201402L
|
||||
return priv_lvl == PRIV_U ? 0x011ULL : priv_lvl == PRIV_S ? 0x000de133ULL : 0x007ff9ddULL;
|
||||
#else
|
||||
switch (priv_lvl) {
|
||||
case PRIV_U: return 0x00000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
|
||||
default:
|
||||
// +-SD
|
||||
// | +-TSR
|
||||
// | |+-TW
|
||||
// | ||+-TVM
|
||||
// | |||+-MXR
|
||||
// | ||||+-SUM
|
||||
// | |||||+-MPRV
|
||||
// | |||||| +-XS
|
||||
// | |||||| | +-FS
|
||||
// | |||||| | | +-MPP
|
||||
// | |||||| | | | +-SPP
|
||||
// | |||||| | | | |+-MPIE
|
||||
// | |||||| | | | || +-UPIE
|
||||
// | ||||||/|/|/| || |+-MIE
|
||||
// | ||||||/|/|/| || || +-UIE
|
||||
return 0b00000000000000000001100010011001;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
using hart_state_type = hart_state<reg_t>;
|
||||
|
||||
constexpr reg_t get_irq_mask(size_t mode) {
|
||||
@ -193,11 +276,15 @@ public:
|
||||
return m[mode];
|
||||
}
|
||||
|
||||
constexpr bool has_compressed() {
|
||||
return traits<BASE>::MISA_VAL&0b0100;
|
||||
}
|
||||
constexpr reg_t get_pc_mask() {
|
||||
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
|
||||
return has_compressed()?~1:~3;
|
||||
}
|
||||
|
||||
riscv_hart_mu_p(feature_config cfg = feature_config{});
|
||||
|
||||
virtual ~riscv_hart_mu_p() = default;
|
||||
|
||||
void reset(uint64_t address) override;
|
||||
@ -218,19 +305,11 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@ -250,26 +329,26 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
virtual uint64_t get_pc() { return arch.get_pc(); };
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
|
||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||
|
||||
uint64_t get_instr_count() { return arch.icount; }
|
||||
uint64_t get_instr_count() override { return arch.reg.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
|
||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
||||
|
||||
riscv_hart_mu_p<BASE, FEAT> &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);
|
||||
@ -302,7 +381,6 @@ protected:
|
||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
|
||||
uint8_t clic_cfg_reg{0};
|
||||
uint32_t clic_info_reg{0};
|
||||
std::array<uint32_t, 32> clic_inttrig_reg;
|
||||
union clic_int_reg_t {
|
||||
struct{
|
||||
@ -314,6 +392,8 @@ protected:
|
||||
uint32_t raw;
|
||||
};
|
||||
std::vector<clic_int_reg_t> clic_int_reg;
|
||||
uint8_t clic_mprev_lvl{0}, clic_uprev_lvl{0};
|
||||
uint8_t clic_mact_lvl{0}, clic_uact_lvl{0};
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
@ -329,6 +409,7 @@ protected:
|
||||
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 read_cause(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);
|
||||
@ -337,8 +418,9 @@ protected:
|
||||
iss::status write_edeleg(unsigned addr, reg_t val);
|
||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
iss::status write_epc(unsigned addr, reg_t val);
|
||||
iss::status write_intstatus(unsigned addr, reg_t val);
|
||||
iss::status read_intstatus(unsigned addr, reg_t& val);
|
||||
iss::status write_intthresh(unsigned addr, reg_t val);
|
||||
iss::status write_xtvt(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_dcsr_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
||||
@ -357,8 +439,6 @@ protected:
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void check_interrupt();
|
||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
||||
@ -367,8 +447,18 @@ protected:
|
||||
std::vector<std::function<mem_write_f>> memfn_write;
|
||||
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
|
||||
feature_config cfg;
|
||||
unsigned mcause_max_irq{16};
|
||||
uint64_t mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||
|
||||
std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
|
||||
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
|
||||
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
|
||||
hart_mem_rd_delegate = rd;
|
||||
hart_mem_wr_delegate = wr;
|
||||
return ret;
|
||||
}
|
||||
std::function<mem_read_f> hart_mem_rd_delegate;
|
||||
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
@ -381,14 +471,13 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr[mvendorid] = 0x669;
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
csr[mclicbase] = cfg.clic_base; // TODO: should be taken from YAML file
|
||||
|
||||
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_csr_reg;
|
||||
}
|
||||
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||
if(traits<BASE>::XLEN==32) for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
@ -399,38 +488,43 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
}
|
||||
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
||||
if(traits<BASE>::XLEN==32) for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
//csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// common regs
|
||||
const std::array<unsigned, 14> addrs{{
|
||||
misa, mvendorid, marchid, mimpid,
|
||||
mepc, mtvec, mscratch, mcause, mtval,
|
||||
uepc, utvec, uscratch, ucause, utval,
|
||||
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
|
||||
for(auto addr: roaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_null;
|
||||
}
|
||||
const std::array<unsigned, 8> rwaddrs{{
|
||||
mepc, mtvec, mscratch, mtval,
|
||||
uepc, utvec, uscratch, utval,
|
||||
}};
|
||||
for(auto addr: addrs) {
|
||||
for(auto addr: rwaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// special handling & overrides
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
csr_rd_cb[timeh] = &this_class::read_time;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[timeh] = &this_class::read_time;
|
||||
csr_rd_cb[cycle] = &this_class::read_cycle;
|
||||
csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||
csr_rd_cb[instret] = &this_class::read_instret;
|
||||
csr_rd_cb[instreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
||||
if(traits<BASE>::XLEN==32) 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;
|
||||
if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret;
|
||||
if(traits<BASE>::XLEN==32) 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_rd_cb[mcause] = &this_class::read_cause;
|
||||
csr_wr_cb[mcause] = &this_class::write_cause;
|
||||
csr_rd_cb[mtvec] = &this_class::read_tvec;
|
||||
csr_wr_cb[mepc] = &this_class::write_epc;
|
||||
@ -451,7 +545,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr_rd_cb[i] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[i] = &this_class::write_csr_reg;
|
||||
}
|
||||
for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
|
||||
for(size_t i=pmpcfg0; i<pmpcfg0+16/sizeof(reg_t); ++i){
|
||||
csr_rd_cb[i] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
|
||||
}
|
||||
@ -468,29 +562,37 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr_wr_cb[uepc] = &this_class::write_epc;
|
||||
csr_rd_cb[ustatus] = &this_class::read_status;
|
||||
csr_wr_cb[ustatus] = &this_class::write_status;
|
||||
csr_rd_cb[ucause] = &this_class::read_cause;
|
||||
csr_wr_cb[ucause] = &this_class::write_cause;
|
||||
csr_rd_cb[utvec] = &this_class::read_tvec;
|
||||
}
|
||||
if(FEAT & FEAT_CLIC) {
|
||||
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mtvt] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintstatus] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mtvt] = &this_class::write_xtvt;
|
||||
// csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintstatus] = &this_class::read_intstatus;
|
||||
csr_wr_cb[mintstatus] = &this_class::write_null;
|
||||
csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||
// csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||
// csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||
// csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
|
||||
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mclicbase] = &this_class::write_null;
|
||||
|
||||
clic_int_reg.resize(cfg.clic_num_irq);
|
||||
clic_cfg_reg=0x20;
|
||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + cfg.clic_num_irq;
|
||||
mcause_max_irq=cfg.clic_num_irq+16;
|
||||
if(FEAT & FEAT_EXT_N){
|
||||
csr_rd_cb[utvt] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[utvt] = &this_class::write_xtvt;
|
||||
csr_rd_cb[uintstatus] = &this_class::read_intstatus;
|
||||
csr_wr_cb[uintstatus] = &this_class::write_null;
|
||||
csr_rd_cb[uintthresh] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[uintthresh] = &this_class::write_intthresh;
|
||||
}
|
||||
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw=0});
|
||||
clic_cfg_reg=0x30;
|
||||
clic_mact_lvl = clic_mprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
clic_uact_lvl = clic_uprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
csr[mintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
csr[uintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
insert_mem_range(cfg.clic_base, 0x5000UL,
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
|
||||
@ -519,6 +621,12 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
||||
}
|
||||
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status {
|
||||
return this->read_mem(a, l, d);
|
||||
};
|
||||
hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status {
|
||||
return this->write_mem(a, l, d);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||
@ -526,10 +634,10 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
if (fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(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
|
||||
@ -582,9 +690,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
@ -619,9 +727,10 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
|
||||
constexpr auto PMP_NAPOT =0x3U;
|
||||
reg_t base = 0;
|
||||
auto any_active = false;
|
||||
auto const cfg_reg_size=sizeof(reg_t);
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT;
|
||||
uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
|
||||
uint8_t cfg = csr[pmpcfg0+(i/cfg_reg_size)]>>(i%cfg_reg_size);
|
||||
if (cfg & PMP_A) {
|
||||
any_active=true;
|
||||
auto pmp_a = (cfg & PMP_A) >> 3;
|
||||
@ -695,7 +804,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
#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){
|
||||
} else if(is_fetch(access)){
|
||||
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else {
|
||||
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
@ -708,26 +817,26 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
if(!pmp_check(access, addr, length) && !is_debug(access)) {
|
||||
fault_data = addr;
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
|
||||
this->reg.trap_state = (1UL << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
auto alignment = is_fetch(access)? (has_compressed()? 2 : 4) : length;
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1UL << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->reg.trap_state = (1UL << 31) | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
@ -735,17 +844,17 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_read[idx](phys_addr, length, data);
|
||||
} else
|
||||
res = read_mem( phys_addr, length, data);
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
} else {
|
||||
res = read_mem( phys_addr, length, data);
|
||||
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -771,7 +880,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -810,25 +919,25 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 1
|
||||
this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 1
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||
if (unlikely(is_fetch(access) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
this->reg.trap_state = (1UL << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||
this->trap_state = 1<<31 | 6<<16;
|
||||
this->reg.trap_state = (1UL << 31) | 6<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
@ -836,45 +945,44 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_write[idx]( phys_addr, length, data);
|
||||
} else
|
||||
res = write_mem( phys_addr, length, data);
|
||||
res = hart_mem_wr_delegate( phys_addr, length, data);
|
||||
} else {
|
||||
res = write_mem( phys_addr, length, data);
|
||||
res = hart_mem_wr_delegate( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 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) {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
switch (addr) {
|
||||
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
|
||||
// LOG(INFO)<<"UART"<<((addr>>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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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;
|
||||
auto &p = mem(addr / mem.page_size);
|
||||
auto offs = addr & 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
|
||||
@ -906,7 +1014,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -952,11 +1060,10 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
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;
|
||||
@ -964,8 +1071,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::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) {
|
||||
@ -974,38 +1079,35 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
val = static_cast<reg_t>(this->instret);
|
||||
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->instret >> 32);
|
||||
val = static_cast<reg_t>(this->reg.instret >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
if ((addr&0xff) == (minstreth&0xff))
|
||||
return iss::Err;
|
||||
this->instret = static_cast<uint64_t>(val);
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
this->instret = (this->instret & 0xffffffff00000000) + val;
|
||||
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
|
||||
} else {
|
||||
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
|
||||
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
|
||||
}
|
||||
}
|
||||
this->instret--;
|
||||
this->reg.instret--;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
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) {
|
||||
@ -1016,24 +1118,60 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) {
|
||||
val = csr[addr] & ~2;
|
||||
val = FEAT & features_e::FEAT_CLIC? csr[addr] : csr[addr] & ~2;
|
||||
return iss::Ok;
|
||||
}
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
|
||||
val = state.mstatus & hart_state_type::get_mask((addr >> 8) & 0x3);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
state.write_mstatus(val, req_priv_lvl);
|
||||
state.write_mstatus(val, (addr >> 8) & 0x3);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||
auto mode = (addr >> 8) & 0x3;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
val |= clic_uprev_lvl<<16;
|
||||
val |= state.mstatus.UPIE<<27;
|
||||
break;
|
||||
default:
|
||||
val |= clic_mprev_lvl<<16;
|
||||
val |= state.mstatus.MPIE<<27;
|
||||
val |= state.mstatus.MPP<<28;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1));
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||
auto mode = (addr >> 8) & 0x3;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
clic_uprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
|
||||
state.mstatus.UPIE=(val>>27)&0x1;
|
||||
break;
|
||||
default:
|
||||
clic_mprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
|
||||
state.mstatus.MPIE=(val>>27)&0x1;
|
||||
state.mstatus.MPP=(val>>28)&0x3;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -1121,28 +1259,30 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||
auto mode = (addr >> 8) & 0x3;
|
||||
val = clic_uact_lvl&0xff;
|
||||
if(mode==0x3)
|
||||
val += (clic_mact_lvl&0xff) <<24;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
|
||||
csr[addr]= val &0xff;
|
||||
csr[addr]= (val &0xff) | (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||
csr[addr]= val & ~0x3fULL;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::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->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
|
||||
@ -1154,31 +1294,14 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::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];
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||
uart_buf.str("");
|
||||
}
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
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));
|
||||
@ -1200,7 +1323,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1234,8 +1357,6 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned lengt
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
*data=clic_cfg_reg;
|
||||
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||
} else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+8)){ // clicinfo
|
||||
read_reg_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
@ -1251,16 +1372,14 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned lengt
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
clic_cfg_reg = *data;
|
||||
clic_cfg_reg&= 0x7e;
|
||||
// } else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+4)){ // clicinfo
|
||||
// write_uint32(addr, clic_info_reg, data, length);
|
||||
clic_cfg_reg = (clic_cfg_reg&~0x1e) | (*data&0x1e);
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
clic_int_reg[offset].raw &= 0xf0c70101; // clicIntCtlBits->0xf0, clicintattr->0xc7, clicintie->0x1, clicintip->0x1
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
@ -1271,6 +1390,7 @@ template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::check_interrupt() {
|
||||
//TODO: Implement CLIC functionality
|
||||
auto ideleg = csr[mideleg];
|
||||
// Multiple simultaneous interrupts and traps at the same privilege level are
|
||||
// handled in the following decreasing priority order:
|
||||
@ -1278,8 +1398,8 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
|
||||
// any synchronous traps.
|
||||
auto ena_irq = csr[mip] & csr[mie];
|
||||
|
||||
bool mie = state.mstatus.MIE;
|
||||
auto m_enabled = this->reg.PRIV < PRIV_M || mie;
|
||||
bool mstatus_mie = state.mstatus.MIE;
|
||||
auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie;
|
||||
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
|
||||
|
||||
if (enabled_interrupts != 0) {
|
||||
@ -1288,14 +1408,14 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||
// calculate and write mcause val
|
||||
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->trap_state;
|
||||
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state;
|
||||
auto trap_id = bit_sub<0, 16>(flags);
|
||||
auto cause = bit_sub<16, 15>(flags);
|
||||
if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause
|
||||
@ -1318,7 +1438,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
csr[utval | (new_priv << 8)] = static_cast<reg_t>(addr);
|
||||
break;
|
||||
case 2:
|
||||
csr[utval | (new_priv << 8)] = (instr & 0x3)==3?instr:instr&0xffff;
|
||||
csr[utval | (new_priv << 8)] = (!has_compressed() || (instr & 0x3)==3)?instr:instr&0xffff;
|
||||
break;
|
||||
case 3:
|
||||
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||
@ -1342,7 +1462,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||
new_priv = PRIV_U;
|
||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||
this->pending_trap = 0;
|
||||
this->reg.pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||
@ -1368,13 +1488,26 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
}
|
||||
|
||||
// get trap vector
|
||||
auto ivec = csr[utvec | (new_priv << 8)];
|
||||
auto xtvec = csr[utvec | (new_priv << 8)];
|
||||
// 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;
|
||||
if((FEAT & features_e::FEAT_CLIC) && trap_id!=0 && (xtvec & 0x3UL)==3UL) {
|
||||
reg_t data;
|
||||
auto ret = read(address_type::LOGICAL, access_type::READ, 0, csr[mtvt], sizeof(reg_t), reinterpret_cast<uint8_t*>(&data));
|
||||
if(ret == iss::Err)
|
||||
return this->reg.PC;
|
||||
this->reg.NEXT_PC = data;
|
||||
} else {
|
||||
this->reg.NEXT_PC = xtvec & ~0x3UL;
|
||||
if ((xtvec & 0x1) == 1 && trap_id != 0)
|
||||
this->reg.NEXT_PC += 4 * cause;
|
||||
}
|
||||
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 << ")"
|
||||
@ -1382,7 +1515,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
<< lvl[this->reg.PRIV] << " to " << lvl[new_priv];
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->trap_state = 0;
|
||||
this->reg.trap_state = 0;
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
@ -1391,7 +1524,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
auto inst_priv = (flags & 0x3)? 3:0;
|
||||
if(inst_priv>cur_priv){
|
||||
auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction
|
||||
this->trap_state = trap_val;
|
||||
this->reg.trap_state = trap_val;
|
||||
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
auto status = state.mstatus;
|
@ -30,9 +30,9 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "tgc_c.h"
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/tgc_c.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
@ -41,8 +41,8 @@ using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
|
||||
tgc_c::tgc_c() = default;
|
||||
|
||||
@ -55,15 +55,15 @@ void tgc_c::reset(uint64_t address) {
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
trap_state=0;
|
||||
icount=0;
|
||||
reg.trap_state=0;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &addr) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc_c>::addr_mask);
|
||||
}
|
||||
|
@ -53,12 +53,12 @@ template <> struct traits<tgc_c> {
|
||||
static constexpr std::array<const char*, 36> reg_aliases{
|
||||
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
|
||||
|
||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, RFS=32, INSTR_ALIGNMENT=2, XLEN=32, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
|
||||
enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
enum reg_e {
|
||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS
|
||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
@ -71,19 +71,19 @@ template <> struct traits<tgc_c> {
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 36> 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}};
|
||||
static constexpr std::array<const uint32_t, 43> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64,32,32}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 36> 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}};
|
||||
static constexpr std::array<const uint32_t, 43> reg_byte_offsets{
|
||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
enum mem_type_e { MEM, FENCE, RES, CSR };
|
||||
|
||||
enum class opcode_e : unsigned short {
|
||||
enum class opcode_e {
|
||||
LUI = 0,
|
||||
AUIPC = 1,
|
||||
JAL = 2,
|
||||
@ -124,56 +124,53 @@ template <> struct traits<tgc_c> {
|
||||
FENCE = 37,
|
||||
ECALL = 38,
|
||||
EBREAK = 39,
|
||||
URET = 40,
|
||||
SRET = 41,
|
||||
MRET = 42,
|
||||
WFI = 43,
|
||||
DRET = 44,
|
||||
CSRRW = 45,
|
||||
CSRRS = 46,
|
||||
CSRRC = 47,
|
||||
CSRRWI = 48,
|
||||
CSRRSI = 49,
|
||||
CSRRCI = 50,
|
||||
FENCE_I = 51,
|
||||
MUL = 52,
|
||||
MULH = 53,
|
||||
MULHSU = 54,
|
||||
MULHU = 55,
|
||||
DIV = 56,
|
||||
DIVU = 57,
|
||||
REM = 58,
|
||||
REMU = 59,
|
||||
CADDI4SPN = 60,
|
||||
CLW = 61,
|
||||
CSW = 62,
|
||||
CADDI = 63,
|
||||
CNOP = 64,
|
||||
CJAL = 65,
|
||||
CLI = 66,
|
||||
CLUI = 67,
|
||||
CADDI16SP = 68,
|
||||
__reserved_clui = 69,
|
||||
CSRLI = 70,
|
||||
CSRAI = 71,
|
||||
CANDI = 72,
|
||||
CSUB = 73,
|
||||
CXOR = 74,
|
||||
COR = 75,
|
||||
CAND = 76,
|
||||
CJ = 77,
|
||||
CBEQZ = 78,
|
||||
CBNEZ = 79,
|
||||
CSLLI = 80,
|
||||
CLWSP = 81,
|
||||
CMV = 82,
|
||||
CJR = 83,
|
||||
__reserved_cmv = 84,
|
||||
CADD = 85,
|
||||
CJALR = 86,
|
||||
CEBREAK = 87,
|
||||
CSWSP = 88,
|
||||
DII = 89,
|
||||
MRET = 40,
|
||||
WFI = 41,
|
||||
CSRRW = 42,
|
||||
CSRRS = 43,
|
||||
CSRRC = 44,
|
||||
CSRRWI = 45,
|
||||
CSRRSI = 46,
|
||||
CSRRCI = 47,
|
||||
FENCE_I = 48,
|
||||
MUL = 49,
|
||||
MULH = 50,
|
||||
MULHSU = 51,
|
||||
MULHU = 52,
|
||||
DIV = 53,
|
||||
DIVU = 54,
|
||||
REM = 55,
|
||||
REMU = 56,
|
||||
CADDI4SPN = 57,
|
||||
CLW = 58,
|
||||
CSW = 59,
|
||||
CADDI = 60,
|
||||
CNOP = 61,
|
||||
CJAL = 62,
|
||||
CLI = 63,
|
||||
CLUI = 64,
|
||||
CADDI16SP = 65,
|
||||
__reserved_clui = 66,
|
||||
CSRLI = 67,
|
||||
CSRAI = 68,
|
||||
CANDI = 69,
|
||||
CSUB = 70,
|
||||
CXOR = 71,
|
||||
COR = 72,
|
||||
CAND = 73,
|
||||
CJ = 74,
|
||||
CBEQZ = 75,
|
||||
CBNEZ = 76,
|
||||
CSLLI = 77,
|
||||
CLWSP = 78,
|
||||
CMV = 79,
|
||||
CJR = 80,
|
||||
__reserved_cmv = 81,
|
||||
CADD = 82,
|
||||
CJALR = 83,
|
||||
CEBREAK = 84,
|
||||
CSWSP = 85,
|
||||
DII = 86,
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
@ -192,25 +189,17 @@ struct tgc_c: public arch_if {
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return icount; }
|
||||
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 last_branch; }
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -251,21 +240,20 @@ struct tgc_c: public arch_if {
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint8_t PRIV = 0;
|
||||
uint32_t DPC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
175
src/iss/arch/tgc_c_decoder.cpp
Normal file
175
src/iss/arch/tgc_c_decoder.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
#include "tgc_c.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
namespace {
|
||||
// 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
|
||||
|
||||
using opcode_e = traits<tgc_c>::opcode_e;
|
||||
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_desriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e op;
|
||||
};
|
||||
|
||||
const std::array<instruction_desriptor, 90> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */
|
||||
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, opcode_e::LUI},
|
||||
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, opcode_e::AUIPC},
|
||||
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, opcode_e::JAL},
|
||||
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, opcode_e::JALR},
|
||||
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, opcode_e::BEQ},
|
||||
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, opcode_e::BNE},
|
||||
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, opcode_e::BLT},
|
||||
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, opcode_e::BGE},
|
||||
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, opcode_e::BLTU},
|
||||
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, opcode_e::BGEU},
|
||||
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, opcode_e::LB},
|
||||
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, opcode_e::LH},
|
||||
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, opcode_e::LW},
|
||||
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, opcode_e::LBU},
|
||||
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, opcode_e::LHU},
|
||||
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, opcode_e::SB},
|
||||
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, opcode_e::SH},
|
||||
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, opcode_e::SW},
|
||||
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, opcode_e::ADDI},
|
||||
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, opcode_e::SLTI},
|
||||
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, opcode_e::SLTIU},
|
||||
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, opcode_e::XORI},
|
||||
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, opcode_e::ORI},
|
||||
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, opcode_e::ANDI},
|
||||
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, opcode_e::SLLI},
|
||||
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRLI},
|
||||
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRAI},
|
||||
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::ADD},
|
||||
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::SUB},
|
||||
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::SLL},
|
||||
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::SLT},
|
||||
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::SLTU},
|
||||
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::XOR},
|
||||
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRL},
|
||||
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRA},
|
||||
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::OR},
|
||||
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::AND},
|
||||
{32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE},
|
||||
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, opcode_e::ECALL},
|
||||
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, opcode_e::EBREAK},
|
||||
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::URET},
|
||||
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::SRET},
|
||||
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::MRET},
|
||||
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, opcode_e::WFI},
|
||||
{32, 0b01111011001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::DRET},
|
||||
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRW},
|
||||
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRS},
|
||||
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRC},
|
||||
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRWI},
|
||||
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRSI},
|
||||
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRCI},
|
||||
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE_I},
|
||||
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::MUL},
|
||||
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::MULH},
|
||||
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::MULHSU},
|
||||
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::MULHU},
|
||||
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::DIV},
|
||||
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::DIVU},
|
||||
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::REM},
|
||||
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::REMU},
|
||||
{16, 0b0000000000000000, 0b1110000000000011, opcode_e::CADDI4SPN},
|
||||
{16, 0b0100000000000000, 0b1110000000000011, opcode_e::CLW},
|
||||
{16, 0b1100000000000000, 0b1110000000000011, opcode_e::CSW},
|
||||
{16, 0b0000000000000001, 0b1110000000000011, opcode_e::CADDI},
|
||||
{16, 0b0000000000000001, 0b1110111110000011, opcode_e::CNOP},
|
||||
{16, 0b0010000000000001, 0b1110000000000011, opcode_e::CJAL},
|
||||
{16, 0b0100000000000001, 0b1110000000000011, opcode_e::CLI},
|
||||
{16, 0b0110000000000001, 0b1110000000000011, opcode_e::CLUI},
|
||||
{16, 0b0110000100000001, 0b1110111110000011, opcode_e::CADDI16SP},
|
||||
{16, 0b0110000000000001, 0b1111000001111111, opcode_e::__reserved_clui},
|
||||
{16, 0b1000000000000001, 0b1111110000000011, opcode_e::CSRLI},
|
||||
{16, 0b1000010000000001, 0b1111110000000011, opcode_e::CSRAI},
|
||||
{16, 0b1000100000000001, 0b1110110000000011, opcode_e::CANDI},
|
||||
{16, 0b1000110000000001, 0b1111110001100011, opcode_e::CSUB},
|
||||
{16, 0b1000110000100001, 0b1111110001100011, opcode_e::CXOR},
|
||||
{16, 0b1000110001000001, 0b1111110001100011, opcode_e::COR},
|
||||
{16, 0b1000110001100001, 0b1111110001100011, opcode_e::CAND},
|
||||
{16, 0b1010000000000001, 0b1110000000000011, opcode_e::CJ},
|
||||
{16, 0b1100000000000001, 0b1110000000000011, opcode_e::CBEQZ},
|
||||
{16, 0b1110000000000001, 0b1110000000000011, opcode_e::CBNEZ},
|
||||
{16, 0b0000000000000010, 0b1111000000000011, opcode_e::CSLLI},
|
||||
{16, 0b0100000000000010, 0b1110000000000011, opcode_e::CLWSP},
|
||||
{16, 0b1000000000000010, 0b1111000000000011, opcode_e::CMV},
|
||||
{16, 0b1000000000000010, 0b1111000001111111, opcode_e::CJR},
|
||||
{16, 0b1000000000000010, 0b1111111111111111, opcode_e::__reserved_cmv},
|
||||
{16, 0b1001000000000010, 0b1111000000000011, opcode_e::CADD},
|
||||
{16, 0b1001000000000010, 0b1111000001111111, opcode_e::CJALR},
|
||||
{16, 0b1001000000000010, 0b1111111111111111, opcode_e::CEBREAK},
|
||||
{16, 0b1100000000000010, 0b1110000000000011, opcode_e::CSWSP},
|
||||
{16, 0b0000000000000000, 0b1111111111111111, opcode_e::DII},
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct instruction_decoder<tgc_c> {
|
||||
using opcode_e = traits<tgc_c>::opcode_e;
|
||||
using code_word_t=traits<tgc_c>::code_word_t;
|
||||
|
||||
struct instruction_pattern {
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
template<typename T>
|
||||
unsigned decode_instruction(T);
|
||||
|
||||
instruction_decoder() {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
unsigned instruction_decoder<tgc_c>::decode_instruction<traits<tgc_c>::code_word_t>(traits<tgc_c>::code_word_t instr){
|
||||
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||
return !((instr&e.mask) ^ e.value );
|
||||
});
|
||||
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<instruction_decoder<tgc_c>> traits<tgc_c>::get_decoder(){
|
||||
return std::make_unique<instruction_decoder<tgc_c>>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,39 +4,46 @@
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_A
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include <iss/arch/tgc_a.h>
|
||||
using tgc_a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_a>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_B
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_b.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_C_XRB_NN
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_c_xrb_nn.h"
|
||||
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
|
||||
#include "hwl.h"
|
||||
#include <iss/arch/tgc_c_xrb_nn.h>
|
||||
using tgc_c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d.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 CORE_TGC_D_XRB_MAC
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d_xrb_mac.h"
|
||||
#include <iss/arch/tgc_d_xrb_mac.h>
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d_xrb_nn.h"
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#include "hwl.h"
|
||||
#include <iss/arch/tgc_d_xrb_nn.h>
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_E
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_e.h"
|
||||
#include <iss/arch/tgc_e.h>
|
||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_X
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_x.h"
|
||||
#include <iss/arch/tgc_x.h>
|
||||
using tgc_x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
|
||||
#endif
|
||||
|
172
src/iss/arch/wt_cache.h
Normal file
172
src/iss/arch/wt_cache.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2023 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_WT_CACHE_H
|
||||
#define _RISCV_HART_M_P_WT_CACHE_H
|
||||
|
||||
#include <iss/vm_types.h>
|
||||
#include <util/ities.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
namespace cache {
|
||||
|
||||
enum class state { INVALID, VALID};
|
||||
struct line {
|
||||
uint64_t tag_addr{0};
|
||||
state st{state::INVALID};
|
||||
std::vector<uint8_t> data;
|
||||
line(unsigned line_sz): data(line_sz) {}
|
||||
};
|
||||
struct set {
|
||||
std::vector<line> ways;
|
||||
set(unsigned ways_count, line const& l): ways(ways_count, l) {}
|
||||
};
|
||||
struct cache {
|
||||
std::vector<set> sets;
|
||||
|
||||
cache(unsigned size, unsigned line_sz, unsigned ways) {
|
||||
line const ref_line{line_sz};
|
||||
set const ref_set{ways, ref_line};
|
||||
sets.resize(size/(ways*line_sz), ref_set);
|
||||
}
|
||||
};
|
||||
|
||||
struct wt_policy {
|
||||
bool is_cacheline_hit(cache& c );
|
||||
};
|
||||
}
|
||||
|
||||
// write thru, allocate on read, direct mapped or set-associative with round-robin replacement policy
|
||||
template <typename BASE> class wt_cache : public BASE {
|
||||
public:
|
||||
using base_class = BASE;
|
||||
using this_class = wt_cache<BASE>;
|
||||
using reg_t = typename BASE::reg_t;
|
||||
using mem_read_f = typename BASE::mem_read_f;
|
||||
using mem_write_f = typename BASE::mem_write_f;
|
||||
using phys_addr_t = typename BASE::phys_addr_t;
|
||||
|
||||
wt_cache();
|
||||
virtual ~wt_cache() = default;
|
||||
|
||||
unsigned size{4096};
|
||||
unsigned line_sz{32};
|
||||
unsigned ways{1};
|
||||
uint64_t io_address{0xf0000000};
|
||||
uint64_t io_addr_mask{0xf0000000};
|
||||
protected:
|
||||
iss::status read_cache(phys_addr_t addr, unsigned, uint8_t *const);
|
||||
iss::status write_cache(phys_addr_t addr, unsigned, uint8_t const *const);
|
||||
std::function<mem_read_f> cache_mem_rd_delegate;
|
||||
std::function<mem_write_f> cache_mem_wr_delegate;
|
||||
std::unique_ptr<cache::cache> dcache_ptr;
|
||||
std::unique_ptr<cache::cache> icache_ptr;
|
||||
size_t get_way_select() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename BASE>
|
||||
inline wt_cache<BASE>::wt_cache() {
|
||||
auto cb = base_class::replace_mem_access(
|
||||
[this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return read_cache(a, l,d);},
|
||||
[this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return write_cache(a, l,d);});
|
||||
cache_mem_rd_delegate = cb.first;
|
||||
cache_mem_wr_delegate = cb.second;
|
||||
}
|
||||
|
||||
template<typename BASE>
|
||||
iss::status iss::arch::wt_cache<BASE>::read_cache(phys_addr_t a, unsigned l, uint8_t* const d) {
|
||||
if(!icache_ptr) {
|
||||
icache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||
}
|
||||
if((a.val&io_addr_mask) != io_address) {
|
||||
auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways);
|
||||
auto tag_addr=a.val>>util::ilog2(line_sz);
|
||||
auto& set = (is_fetch(a.access)?icache_ptr:dcache_ptr)->sets[set_addr];
|
||||
for(auto& cl: set.ways) {
|
||||
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
|
||||
auto start_addr = a.val&(line_sz-1);
|
||||
for(auto i = 0U; i<l; ++i)
|
||||
d[i] = cl.data[start_addr+i];
|
||||
return iss::Ok;
|
||||
}
|
||||
}
|
||||
auto& cl = set.ways[get_way_select()];
|
||||
phys_addr_t cl_addr{a};
|
||||
cl_addr.val=tag_addr<<util::ilog2(line_sz);
|
||||
cache_mem_rd_delegate(cl_addr, line_sz, cl.data.data());
|
||||
cl.tag_addr=tag_addr;
|
||||
cl.st=cache::state::VALID;
|
||||
auto start_addr = a.val&(line_sz-1);
|
||||
for(auto i = 0U; i<l; ++i)
|
||||
d[i] = cl.data[start_addr+i];
|
||||
return iss::Ok;
|
||||
} else
|
||||
return cache_mem_rd_delegate(a, l, d);
|
||||
}
|
||||
|
||||
template<typename BASE>
|
||||
iss::status iss::arch::wt_cache<BASE>::write_cache(phys_addr_t a, unsigned l, const uint8_t* const d) {
|
||||
if(!dcache_ptr)
|
||||
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||
auto res = cache_mem_wr_delegate(a, l, d);
|
||||
if(res == iss::Ok && ((a.val&io_addr_mask) != io_address)) {
|
||||
auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways);
|
||||
auto tag_addr=a.val>>util::ilog2(line_sz);
|
||||
auto& set = dcache_ptr->sets[set_addr];
|
||||
for(auto& cl: set.ways) {
|
||||
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
|
||||
auto start_addr = a.val&(line_sz-1);
|
||||
for(auto i = 0U; i<l; ++i)
|
||||
cl.data[start_addr+i] = d[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace arch
|
||||
} // namespace iss
|
||||
|
||||
#endif /* _RISCV_HART_M_P_H */
|
@ -85,7 +85,7 @@ public:
|
||||
corresponding bytes in avail_buf are 0, otherwise
|
||||
avail buf is 1 */
|
||||
status read_single_register(unsigned int reg_no, std::vector<uint8_t> &buf,
|
||||
std::vector<uint8_t> &avail_buf) override;
|
||||
std::vector<uint8_t> &avail_buf) override;
|
||||
|
||||
/* Write one register. buf is 4-byte aligned and it is in target byte
|
||||
order */
|
||||
@ -104,7 +104,7 @@ public:
|
||||
status process_query(unsigned int &mask, const rp_thread_ref &arg, rp_thread_info &info) override;
|
||||
|
||||
status thread_list_query(int first, const rp_thread_ref &arg, std::vector<rp_thread_ref> &result, size_t max_num,
|
||||
size_t &num, bool &done) override;
|
||||
size_t &num, bool &done) override;
|
||||
|
||||
status current_thread_query(rp_thread_ref &thread) override;
|
||||
|
||||
@ -120,12 +120,12 @@ public:
|
||||
|
||||
status packetsize_query(std::string &out_buf) override;
|
||||
|
||||
status add_break(int type, uint64_t addr, unsigned int length) override;
|
||||
status add_break(break_type type, uint64_t addr, unsigned int length) override;
|
||||
|
||||
status remove_break(int type, uint64_t addr, unsigned int length) override;
|
||||
status remove_break(break_type type, uint64_t addr, unsigned int length) override;
|
||||
|
||||
status resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
|
||||
std::function<void(unsigned)> stop_callback) override;
|
||||
std::function<void(unsigned)> stop_callback) override;
|
||||
|
||||
status target_xml_query(std::string &out_buf) override;
|
||||
|
||||
@ -159,8 +159,8 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::is_thread_alive(rp_t
|
||||
*/
|
||||
template <typename ARCH>
|
||||
status riscv_target_adapter<ARCH>::thread_list_query(int first, const rp_thread_ref &arg,
|
||||
std::vector<rp_thread_ref> &result, size_t max_num, size_t &num,
|
||||
bool &done) {
|
||||
std::vector<rp_thread_ref> &result, size_t max_num, size_t &num,
|
||||
bool &done) {
|
||||
if (first == 0) {
|
||||
result.clear();
|
||||
result.push_back(thread_idx);
|
||||
@ -193,20 +193,20 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
|
||||
|
||||
template <typename ARCH>
|
||||
status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std::vector<uint8_t> &data,
|
||||
std::vector<uint8_t> &avail) {
|
||||
std::vector<uint8_t> &avail) {
|
||||
if (reg_no < 65) {
|
||||
// auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename
|
||||
// arch::traits<ARCH>::reg_e>(reg_no))/8;
|
||||
@ -331,34 +331,48 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::packetsize_query(std
|
||||
return Ok;
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type, uint64_t addr, unsigned int length) {
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
||||
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
||||
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
|
||||
<< saddr.val << std::dec;
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Ok;
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int type, uint64_t addr, unsigned int length) {
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
||||
if (handle) {
|
||||
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val
|
||||
<< std::dec;
|
||||
// TODO: check length of addr range
|
||||
target_adapter_base::bp_lut.removeEntry(handle);
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(break_type type, uint64_t addr, unsigned int length) {
|
||||
switch(type) {
|
||||
default:
|
||||
return Err;
|
||||
case SW_EXEC:
|
||||
case HW_EXEC: {
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
||||
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
||||
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
|
||||
<< saddr.val << std::dec;
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Ok;
|
||||
}
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(break_type type, uint64_t addr, unsigned int length) {
|
||||
switch(type) {
|
||||
default:
|
||||
return Err;
|
||||
case SW_EXEC:
|
||||
case HW_EXEC: {
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
||||
if (handle) {
|
||||
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val
|
||||
<< std::dec;
|
||||
// TODO: check length of addr range
|
||||
target_adapter_base::bp_lut.removeEntry(handle);
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Ok;
|
||||
}
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
status riscv_target_adapter<ARCH>::resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
|
||||
std::function<void(unsigned)> stop_callback) {
|
||||
std::function<void(unsigned)> stop_callback) {
|
||||
auto *reg_base = core->get_regs_base_ptr();
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
|
||||
@ -369,42 +383,42 @@ status riscv_target_adapter<ARCH>::resume_from_addr(bool step, int sig, uint64_t
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std::string &out_buf) {
|
||||
const std::string res{"<?xml version=\"1.0\"?><!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
|
||||
"<target><architecture>riscv:rv32</architecture>"
|
||||
//" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n"
|
||||
//" <reg name=\"x0\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x1\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x2\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x3\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x4\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x5\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x6\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x7\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x8\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x9\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x10\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x11\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x12\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x13\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x14\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x15\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x16\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x17\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x18\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x19\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x20\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x21\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x22\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x23\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x24\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x25\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x26\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x27\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x28\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x29\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x30\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x31\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" </feature>\n"
|
||||
"</target>"};
|
||||
"<target><architecture>riscv:rv32</architecture>"
|
||||
//" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n"
|
||||
//" <reg name=\"x0\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x1\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x2\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x3\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x4\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x5\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x6\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x7\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x8\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x9\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x10\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x11\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x12\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x13\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x14\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x15\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x16\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x17\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x18\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x19\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x20\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x21\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x22\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x23\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x24\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x25\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x26\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x27\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x28\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x29\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x30\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x31\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" </feature>\n"
|
||||
"</target>"};
|
||||
out_buf = res;
|
||||
return Ok;
|
||||
}
|
@ -34,6 +34,12 @@
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
#include <iss/iss.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace iss {
|
||||
|
||||
@ -50,13 +56,51 @@ std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_LLVM
|
||||
#ifdef WITH_TCC
|
||||
if(backend == "tcc")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
|
||||
class core_factory {
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
using base_t = std::tuple<cpu_ptr, vm_ptr>;
|
||||
using create_fn = std::function<base_t(unsigned, void*) >;
|
||||
using registry_t = std::unordered_map<std::string, create_fn> ;
|
||||
|
||||
registry_t registry;
|
||||
|
||||
core_factory() = default;
|
||||
core_factory(const core_factory &) = delete;
|
||||
core_factory & operator=(const core_factory &) = delete;
|
||||
|
||||
public:
|
||||
static core_factory & instance() { static core_factory bf; return bf; }
|
||||
|
||||
bool register_creator(const std::string & className, create_fn const& fn) {
|
||||
registry[className] = fn;
|
||||
return true;
|
||||
}
|
||||
|
||||
base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
|
||||
registry_t::const_iterator regEntry = registry.find(className);
|
||||
if (regEntry != registry.end())
|
||||
return regEntry->second(gdb_port, init_data);
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
std::vector<std::string> get_names() {
|
||||
std::vector<std::string> keys{registry.size()};
|
||||
std::transform(std::begin(registry), std::end(registry), std::begin(keys), [](std::pair<std::string, create_fn> const& p){
|
||||
return p.first;
|
||||
});
|
||||
return keys;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _ISS_FACTORY_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -32,14 +32,14 @@
|
||||
* eyck@minres.com - initial API and implementation
|
||||
******************************************************************************/
|
||||
|
||||
#include "iss/plugin/cycle_estimate.h"
|
||||
#include "cycle_estimate.h"
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <util/logging.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <fstream>
|
||||
@ -107,12 +107,12 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
|
||||
}
|
||||
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
|
||||
assert(instr_if && "No instrumentation interface available but callback executed");
|
||||
auto entry = delays[instr_info.instr_id];
|
||||
bool taken = exc_info.branch_taken;
|
||||
if (exc_info.branch_taken && (entry.taken > 1))
|
||||
instr_if->set_curr_instr_cycles(entry.taken);
|
||||
bool taken = instr_if->is_branch_taken();
|
||||
if (taken && (entry.taken > 1))
|
||||
instr_if->update_last_instr_cycles(entry.taken);
|
||||
else if (entry.not_taken > 1)
|
||||
instr_if->set_curr_instr_cycles(entry.not_taken);
|
||||
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -45,7 +45,7 @@ namespace iss {
|
||||
|
||||
namespace plugin {
|
||||
|
||||
class cycle_estimate: public iss::vm_plugin {
|
||||
class cycle_estimate: public vm_plugin {
|
||||
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||
BF_FIELD(taken, 24, 8)
|
||||
BF_FIELD(not_taken, 16, 8)
|
||||
@ -78,7 +78,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info, exec_info const&) override;
|
||||
void callback(instr_info_t instr_info) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *instr_if;
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -32,8 +32,8 @@
|
||||
* eyck@minres.com - initial API and implementation
|
||||
******************************************************************************/
|
||||
|
||||
#include "iss/plugin/instruction_count.h"
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "instruction_count.h"
|
||||
#include <iss/instrumentation_if.h>
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <util/logging.h>
|
||||
@ -90,6 +90,6 @@ bool iss::plugin::instruction_count::registration(const char* const version, vm_
|
||||
return true;
|
||||
}
|
||||
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info) {
|
||||
rep_counts[instr_info.instr_id]++;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -69,7 +69,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t, exec_info const&) override;
|
||||
void callback(instr_info_t) override;
|
||||
|
||||
private:
|
||||
Json::Value root;
|
@ -1,11 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2023, 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:
|
||||
* alex.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
#include <util/logging.h>
|
||||
#include <util/ities.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <fstream>
|
||||
@ -89,7 +123,7 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
cov::cov(std::string const &filename)
|
||||
pctrace::pctrace(std::string const &filename)
|
||||
: instr_if(nullptr)
|
||||
, filename(filename)
|
||||
, output("output.trc")
|
||||
@ -99,9 +133,9 @@ cov::cov(std::string const &filename)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
cov::~cov() { }
|
||||
pctrace::~pctrace() { }
|
||||
|
||||
bool cov::registration(const char *const version, vm_if& vm) {
|
||||
bool pctrace::registration(const char *const version, vm_if& vm) {
|
||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||
if(!instr_if) return false;
|
||||
const string core_name = instr_if->core_type_name();
|
||||
@ -152,22 +186,22 @@ bool cov::registration(const char *const version, vm_if& vm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
||||
void pctrace::callback(instr_info_t iinfo) {
|
||||
auto delay = 0;
|
||||
size_t id = iinfo.instr_id;
|
||||
auto entry = delays[id];
|
||||
auto instr = instr_if->get_instr_word();
|
||||
auto call = id==65 || id ==86 || ((id==2 || id==3) && bit_sub<7,5>(instr)!=0) ;//not taking care of tail calls (jalr with loading x6)
|
||||
bool taken = einfo.branch_taken;
|
||||
bool taken = instr_if->is_branch_taken();
|
||||
bool compressed = (instr&0x3)!=0x3;
|
||||
if (einfo.branch_taken) {
|
||||
if (taken) {
|
||||
delay = entry.taken;
|
||||
if(entry.taken > 1)
|
||||
instr_if->set_curr_instr_cycles(entry.taken);
|
||||
instr_if->update_last_instr_cycles(entry.taken);
|
||||
} else {
|
||||
delay = entry.not_taken;
|
||||
if (entry.not_taken > 1)
|
||||
instr_if->set_curr_instr_cycles(entry.not_taken);
|
||||
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||
}
|
||||
#ifndef WITH_LZ4
|
||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -37,7 +37,6 @@
|
||||
|
||||
#include <iss/vm_plugin.h>
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
@ -45,7 +44,7 @@
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
class lz4compress_steambuf;
|
||||
class cov : public iss::vm_plugin {
|
||||
class pctrace : public iss::vm_plugin {
|
||||
struct instr_delay {
|
||||
std::string instr_name;
|
||||
size_t size;
|
||||
@ -67,23 +66,23 @@ class cov : public iss::vm_plugin {
|
||||
|
||||
public:
|
||||
|
||||
cov(const cov &) = delete;
|
||||
pctrace(const pctrace &) = delete;
|
||||
|
||||
cov(const cov &&) = delete;
|
||||
pctrace(const pctrace &&) = delete;
|
||||
|
||||
cov(std::string const &);
|
||||
pctrace(std::string const &);
|
||||
|
||||
virtual ~cov();
|
||||
virtual ~pctrace();
|
||||
|
||||
cov &operator=(const cov &) = delete;
|
||||
pctrace &operator=(const pctrace &) = delete;
|
||||
|
||||
cov &operator=(const cov &&) = delete;
|
||||
pctrace &operator=(const pctrace &&) = delete;
|
||||
|
||||
bool registration(const char *const version, vm_if &arch) override;
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t, exec_info const&) override;
|
||||
void callback(instr_info_t) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *instr_if {nullptr};
|
454
src/main.cpp
454
src/main.cpp
@ -1,236 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* 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 <iostream>
|
||||
#include <iss/factory.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#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>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
#include <iss/plugin/loader.h>
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
*/
|
||||
po::variables_map clim;
|
||||
po::options_description desc("Options");
|
||||
// clang-format off
|
||||
desc.add_options()
|
||||
("help,h", "Print help message")
|
||||
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||
("reset,r", po::value<std::string>(), "reset address")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf,f", 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("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 {
|
||||
po::store(parsed, clim); // can throw
|
||||
// --help option
|
||||
if (clim.count("help")) {
|
||||
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
|
||||
return 0;
|
||||
}
|
||||
po::notify(clim); // throws on error, so do after help in case
|
||||
} catch (po::error &e) {
|
||||
// there are problems
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
||||
|
||||
LOGGER(DEFAULT)::print_time() = false;
|
||||
LOGGER(connection)::print_time() = false;
|
||||
if (clim.count("verbose")) {
|
||||
auto l = logging::as_log_level(clim["verbose"].as<int>());
|
||||
LOGGER(DEFAULT)::reporting_level() = l;
|
||||
LOGGER(connection)::reporting_level() = l;
|
||||
}
|
||||
if (clim.count("logfile")) {
|
||||
// configure the connection logger
|
||||
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
|
||||
LOG_OUTPUT(DEFAULT)::stream() = f;
|
||||
LOG_OUTPUT(connection)::stream() = f;
|
||||
}
|
||||
|
||||
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
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
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_C_XRB_NN
|
||||
if (isa_opt == "tgc_c_xrb_nn") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_c_xrb_nn_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
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
if (isa_opt == "tgc_d_xrb_mac") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
if (isa_opt == "tgc_d_xrb_nn") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_E
|
||||
if (isa_opt == "tgc_e") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
|
||||
return 127;
|
||||
}
|
||||
if (clim.count("plugin")) {
|
||||
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) {
|
||||
plugin_name = opt_val.substr(0, found);
|
||||
filename = opt_val.substr(found + 1, opt_val.size());
|
||||
}
|
||||
if (plugin_name == "ic") {
|
||||
auto *ic_plugin = new iss::plugin::instruction_count(filename);
|
||||
vm->register_plugin(*ic_plugin);
|
||||
plugin_list.push_back(ic_plugin);
|
||||
} else if (plugin_name == "ce") {
|
||||
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::cov(filename);
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
if(plugin){
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
/*******************************************************************************
|
||||
* 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 <iostream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iss/factory.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include "iss/arch/tgc_mapper.h"
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_init.h>
|
||||
#endif
|
||||
#include <iss/log_categories.h>
|
||||
#include "iss/plugin/cycle_estimate.h"
|
||||
#include "iss/plugin/instruction_count.h"
|
||||
#include "iss/plugin/pctrace.h"
|
||||
#ifndef WIN32
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
*/
|
||||
po::variables_map clim;
|
||||
po::options_description desc("Options");
|
||||
// clang-format off
|
||||
desc.add_options()
|
||||
("help,h", "Print help message")
|
||||
("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity")
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||
("reset,r", po::value<std::string>(), "reset address")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf,f", 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("interp"), "the ISS backend to use, options are: interp, tcc")
|
||||
("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 {
|
||||
po::store(parsed, clim); // can throw
|
||||
// --help option
|
||||
if (clim.count("help")) {
|
||||
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
|
||||
return 0;
|
||||
}
|
||||
po::notify(clim); // throws on error, so do after help in case
|
||||
} catch (po::error &e) {
|
||||
// there are problems
|
||||
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
||||
|
||||
LOGGER(DEFAULT)::print_time() = false;
|
||||
LOGGER(connection)::print_time() = false;
|
||||
auto l = logging::as_log_level(clim["verbose"].as<int>());
|
||||
LOGGER(DEFAULT)::reporting_level() = l;
|
||||
LOGGER(connection)::reporting_level() = l;
|
||||
if (clim.count("logfile")) {
|
||||
// configure the connection logger
|
||||
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
|
||||
LOG_OUTPUT(DEFAULT)::stream() = f;
|
||||
LOG_OUTPUT(connection)::stream() = f;
|
||||
}
|
||||
|
||||
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");
|
||||
auto & f = iss::core_factory::instance();
|
||||
// instantiate the simulator
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if(isa_opt.size()==0 || isa_opt == "?") {
|
||||
std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
|
||||
return 0;
|
||||
} else if (isa_opt.find('|') != std::string::npos) {
|
||||
std::tie(cpu, vm) = f.create(isa_opt+"|"+clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else {
|
||||
auto base_isa = isa_opt.substr(0, 5);
|
||||
if(base_isa=="tgc_d" || base_isa=="tgc_e") {
|
||||
isa_opt += "|mu_p_clic_pmp|"+clim["backend"].as<std::string>();
|
||||
} else {
|
||||
isa_opt += "|m_p|"+clim["backend"].as<std::string>();
|
||||
}
|
||||
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>());
|
||||
}
|
||||
if(!cpu ){
|
||||
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
if(!vm ){
|
||||
LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||
return 127;
|
||||
}
|
||||
if (clim.count("plugin")) {
|
||||
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
|
||||
std::string plugin_name=opt_val;
|
||||
std::string arg{""};
|
||||
std::size_t found = opt_val.find('=');
|
||||
if (found != std::string::npos) {
|
||||
plugin_name = opt_val.substr(0, found);
|
||||
arg = opt_val.substr(found + 1, opt_val.size());
|
||||
}
|
||||
if (plugin_name == "ic") {
|
||||
auto *ic_plugin = new iss::plugin::instruction_count(arg);
|
||||
vm->register_plugin(*ic_plugin);
|
||||
plugin_list.push_back(ic_plugin);
|
||||
} else if (plugin_name == "ce") {
|
||||
auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::pctrace(arg);
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
#ifndef WIN32
|
||||
std::vector<char const*> a{};
|
||||
if(arg.length())
|
||||
a.push_back({arg.c_str()});
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
if(plugin){
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clim.count("disass")) {
|
||||
vm->setDisassEnabled(true);
|
||||
LOGGER(disass)::reporting_level() = logging::INFO;
|
||||
LOGGER(disass)::print_time() = false;
|
||||
auto file_name = clim["disass"].as<std::string>();
|
||||
if (file_name.length() > 0) {
|
||||
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
|
||||
LOGGER(disass)::print_severity() = false;
|
||||
}
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("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);
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
for (std::string input : args) {
|
||||
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
if (clim.count("reset")) {
|
||||
auto str = clim["reset"].as<std::string>();
|
||||
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
|
||||
}
|
||||
vm->reset(start_address);
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
} catch (std::exception &e) {
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clim.count("disass")) {
|
||||
vm->setDisassEnabled(true);
|
||||
LOGGER(disass)::reporting_level() = logging::INFO;
|
||||
LOGGER(disass)::print_time() = false;
|
||||
auto file_name = clim["disass"].as<std::string>();
|
||||
if (file_name.length() > 0) {
|
||||
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
|
||||
LOGGER(disass)::print_severity() = false;
|
||||
}
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("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);
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
for (std::string input : args) {
|
||||
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
|
||||
if (start_addr.second) start_address = start_addr.first;
|
||||
}
|
||||
if (clim.count("reset")) {
|
||||
auto str = clim["reset"].as<std::string>();
|
||||
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
|
||||
}
|
||||
vm->reset(start_address);
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
} catch (std::exception &e) {
|
||||
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||
<< std::endl;
|
||||
res = 2;
|
||||
}
|
||||
// cleanup to let plugins report of needed
|
||||
for (auto *p : plugin_list) {
|
||||
delete p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
<< std::endl;
|
||||
res = 2;
|
||||
}
|
||||
// cleanup to let plugins report of needed
|
||||
for (auto *p : plugin_list) {
|
||||
delete p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -30,15 +30,18 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
// 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>
|
||||
// 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 <iss/plugin/loader.h>
|
||||
#include <sysc/core_complex.h>
|
||||
#include "iss_factory.h"
|
||||
#ifndef WIN32
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
@ -49,7 +52,7 @@
|
||||
#include <iss/plugin/instruction_count.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
|
||||
#define STR(X) #X
|
||||
#define CREATE_CORE(CN) \
|
||||
@ -68,12 +71,12 @@ using namespace scv_tr;
|
||||
#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
|
||||
|
||||
#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 tgfs {
|
||||
using namespace std;
|
||||
@ -83,135 +86,9 @@ using namespace sc_core;
|
||||
|
||||
namespace {
|
||||
iss::debugger::encoder_decoder encdec;
|
||||
|
||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
}
|
||||
|
||||
template<typename PLAT>
|
||||
class core_wrapper_t : public PLAT {
|
||||
public:
|
||||
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.PRIV; }
|
||||
|
||||
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
|
||||
|
||||
inline bool get_interrupt_execution() { return this->interrupt_sim; }
|
||||
|
||||
heart_state_t &get_state() { return this->state; }
|
||||
|
||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||
if (p == iss::arch_if::ISTART) owner->sync(this->icount);
|
||||
}
|
||||
|
||||
sync_type needed_sync() const override { return PRE_SYNC; }
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
if (!owner->disass_output(pc, instr)) {
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
|
||||
<< this->icount + this->cycle_offset << "]";
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
|
||||
if (addr.access && access_type::DEBUG)
|
||||
return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
|
||||
else {
|
||||
return owner->read_mem(addr.val, length, data, addr.access && access_type::FETCH) ? Ok : Err;
|
||||
}
|
||||
}
|
||||
|
||||
status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override {
|
||||
if (addr.access && access_type::DEBUG)
|
||||
return owner->write_mem_dbg(addr.val, length, data) ? Ok : Err;
|
||||
else {
|
||||
auto res = owner->write_mem(addr.val, length, data) ? Ok : Err;
|
||||
// clear MTIP on mtimecmp write
|
||||
if (addr.val == 0x2004000) {
|
||||
reg_t val;
|
||||
this->read_csr(arch::mip, val);
|
||||
if (val & (1ULL << 7)) this->write_csr(arch::mip, val & ~(1ULL << 7));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 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 PLAT::read_csr(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_until(uint64_t flags) override {
|
||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||
while(this->pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
|
||||
sc_core::wait(wfi_evt);
|
||||
}
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
void local_irq(short id, bool value) {
|
||||
reg_t mask = 0;
|
||||
switch (id) {
|
||||
case 16: // SW
|
||||
mask = 1 << 3;
|
||||
break;
|
||||
case 17: // timer
|
||||
mask = 1 << 7;
|
||||
break;
|
||||
case 18: // external
|
||||
mask = 1 << 11;
|
||||
break;
|
||||
default:
|
||||
/* do nothing*/
|
||||
break;
|
||||
}
|
||||
if (value) {
|
||||
this->csr[arch::mip] |= mask;
|
||||
wfi_evt.notify();
|
||||
} else
|
||||
this->csr[arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
core_complex *const owner;
|
||||
sc_event wfi_evt;
|
||||
};
|
||||
|
||||
int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func df,
|
||||
debugger::target_adapter_if *tgt_adapter) {
|
||||
if (argc > 1) {
|
||||
@ -251,7 +128,9 @@ public:
|
||||
|
||||
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);};
|
||||
inline std::pair<uint64_t, bool> load_file(std::string const& name){
|
||||
iss::arch_if* cc = cpu->get_arch_if();
|
||||
return cc->load_file(name);};
|
||||
|
||||
std::function<unsigned(void)> get_mode;
|
||||
std::function<uint64_t(void)> get_state;
|
||||
@ -259,45 +138,35 @@ public:
|
||||
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
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
CREATE_CORE(tgc_d_xrb_mac)
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
CREATE_CORE(tgc_d_xrb_nn)
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
|
||||
auto & f = sysc::iss_factory::instance();
|
||||
if(type.size()==0 || type == "?") {
|
||||
std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
|
||||
sc_core::sc_stop();
|
||||
} else if (type.find('|') != std::string::npos) {
|
||||
std::tie(cpu, vm) = f.create(type+"|"+backend);
|
||||
} else {
|
||||
auto base_isa = type.substr(0, 5);
|
||||
if(base_isa=="tgc_d" || base_isa=="tgc_e") {
|
||||
std::tie(cpu, vm) = f.create(type + "|mu_p_clic_pmp|" + backend, gdb_port, owner);
|
||||
} else {
|
||||
std::tie(cpu, vm) = f.create(type + "|m_p|" + backend, gdb_port, owner);
|
||||
}
|
||||
}
|
||||
if(!cpu ){
|
||||
SCCFATAL() << "Could not create cpu for isa " << type << " and backend " <<backend;
|
||||
}
|
||||
if(!vm ){
|
||||
SCCFATAL() << "Could not create vm for isa " << type << " and backend " <<backend;
|
||||
}
|
||||
auto* sc_cpu_if = reinterpret_cast<sc_core_adapter_if*>(cpu.get());
|
||||
sc_cpu_if->set_mhartid(hart_id);
|
||||
get_mode = [sc_cpu_if]() { return sc_cpu_if->get_mode(); };
|
||||
get_state = [sc_cpu_if]() { return sc_cpu_if->get_state(); };
|
||||
get_interrupt_execution = [sc_cpu_if]() { return sc_cpu_if->get_interrupt_execution(); };
|
||||
set_interrupt_execution = [sc_cpu_if](bool b) { return sc_cpu_if->set_interrupt_execution(b); };
|
||||
local_irq = [sc_cpu_if](short s, bool b) { return sc_cpu_if->local_irq(s, b); };
|
||||
|
||||
auto *srv = debugger::server<debugger::gdb_session>::get();
|
||||
if (srv) tgt_adapter = srv->get_target();
|
||||
if (tgt_adapter)
|
||||
@ -310,7 +179,7 @@ public:
|
||||
|
||||
core_complex * const owner;
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
sc_cpu_ptr cpu{nullptr};
|
||||
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
|
||||
};
|
||||
|
||||
@ -328,6 +197,7 @@ SC_HAS_PROCESS(core_complex);// NOLINT
|
||||
#ifndef CWR_SYSTEMC
|
||||
core_complex::core_complex(sc_module_name const& name)
|
||||
: sc_module(name)
|
||||
, fetch_lut(tlm_dmi_ext())
|
||||
, read_lut(tlm_dmi_ext())
|
||||
, write_lut(tlm_dmi_ext())
|
||||
{
|
||||
@ -337,7 +207,13 @@ core_complex::core_complex(sc_module_name const& name)
|
||||
|
||||
void core_complex::init(){
|
||||
trc=new core_trace();
|
||||
initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||
ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||
auto lut_entry = fetch_lut.getEntry(start);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
|
||||
fetch_lut.removeEntry(lut_entry);
|
||||
}
|
||||
});
|
||||
dbus.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) {
|
||||
read_lut.removeEntry(lut_entry);
|
||||
@ -355,8 +231,11 @@ void core_complex::init(){
|
||||
sensitive << sw_irq_i;
|
||||
SC_METHOD(timer_irq_cb);
|
||||
sensitive << timer_irq_i;
|
||||
SC_METHOD(global_irq_cb);
|
||||
sensitive << global_irq_i;
|
||||
SC_METHOD(ext_irq_cb);
|
||||
sensitive << ext_irq_i;
|
||||
SC_METHOD(local_irq_cb);
|
||||
for(auto pin:local_irq_i)
|
||||
sensitive << pin;
|
||||
trc->m_db=scv_tr_db::get_default_db();
|
||||
|
||||
SC_METHOD(forward);
|
||||
@ -405,10 +284,11 @@ void core_complex::before_end_of_elaboration() {
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::cov(filename);
|
||||
auto *plugin = new iss::plugin::pctrace(filename);
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
#ifndef WIN32
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
@ -416,6 +296,7 @@ void core_complex::before_end_of_elaboration() {
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else
|
||||
#endif
|
||||
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
|
||||
}
|
||||
}
|
||||
@ -424,7 +305,7 @@ void core_complex::before_end_of_elaboration() {
|
||||
}
|
||||
|
||||
void core_complex::start_of_simulation() {
|
||||
quantum_keeper.reset();
|
||||
// quantum_keeper.reset();
|
||||
if (GET_PROP_VALUE(elf_file).size() > 0) {
|
||||
istringstream is(GET_PROP_VALUE(elf_file));
|
||||
string s;
|
||||
@ -476,15 +357,24 @@ void core_complex::rst_cb() {
|
||||
if (rst_i.read()) cpu->set_interrupt_execution(true);
|
||||
}
|
||||
|
||||
void core_complex::sw_irq_cb() { cpu->local_irq(16, sw_irq_i.read()); }
|
||||
void core_complex::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); }
|
||||
|
||||
void core_complex::timer_irq_cb() { cpu->local_irq(17, timer_irq_i.read()); }
|
||||
void core_complex::timer_irq_cb() { cpu->local_irq(7, timer_irq_i.read()); }
|
||||
|
||||
void core_complex::global_irq_cb() { cpu->local_irq(18, global_irq_i.read()); }
|
||||
void core_complex::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); }
|
||||
|
||||
void core_complex::local_irq_cb() {
|
||||
for(auto i=0U; i<local_irq_i.size(); ++i) {
|
||||
if(local_irq_i[i].event()) {
|
||||
cpu->local_irq(16+i, local_irq_i[i].read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void core_complex::run() {
|
||||
wait(SC_ZERO_TIME); // separate from elaboration phase
|
||||
do {
|
||||
wait(SC_ZERO_TIME);
|
||||
if (rst_i.read()) {
|
||||
cpu->reset(GET_PROP_VALUE(reset_address));
|
||||
wait(rst_i.negedge_event());
|
||||
@ -492,6 +382,7 @@ void core_complex::run() {
|
||||
while (curr_clk.read() == SC_ZERO_TIME) {
|
||||
wait(curr_clk.value_changed_event());
|
||||
}
|
||||
quantum_keeper.reset();
|
||||
cpu->set_interrupt_execution(false);
|
||||
cpu->start();
|
||||
} while (cpu->get_interrupt_execution());
|
||||
@ -499,14 +390,15 @@ void core_complex::run() {
|
||||
}
|
||||
|
||||
bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch) {
|
||||
auto lut_entry = read_lut.getEntry(addr);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
||||
addr + length <= lut_entry.get_end_address() + 1) {
|
||||
auto& dmi_lut = is_fetch?fetch_lut:read_lut;
|
||||
auto lut_entry = dmi_lut.getEntry(addr);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
|
||||
auto offset = addr - lut_entry.get_start_address();
|
||||
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||
return true;
|
||||
} else {
|
||||
auto& sckt = is_fetch? ibus : dbus;
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
@ -521,8 +413,13 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
initiator->b_transport(gp, delay);
|
||||
SCCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
|
||||
sckt->b_transport(gp, delay);
|
||||
auto incr = delay-quantum_keeper.get_local_time();
|
||||
if(is_fetch)
|
||||
ibus_inc+=incr;
|
||||
else
|
||||
dbus_inc+=incr;
|
||||
SCCTRACE(this->name()) << "[local time: "<<delay<<"]: finish read_mem(0x" << std::hex << addr << ") : 0x" << (length==4?*(uint32_t*)data:length==2?*(uint16_t*)data:(unsigned)*data);
|
||||
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
||||
return false;
|
||||
}
|
||||
@ -530,13 +427,10 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
tlm_dmi_ext dmi_data;
|
||||
if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
|
||||
if (sckt->get_direct_mem_ptr(gp, dmi_data)) {
|
||||
if (dmi_data.is_read_allowed())
|
||||
read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||
dmi_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||
if (dmi_data.is_write_allowed())
|
||||
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -565,9 +459,9 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
initiator->b_transport(gp, delay);
|
||||
quantum_keeper.set(delay);
|
||||
SCCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
|
||||
dbus->b_transport(gp, delay);
|
||||
dbus_inc+=delay-quantum_keeper.get_local_time();
|
||||
SCCTRACE() << "[local time: "<<delay<<"]: finish write_mem(0x" << std::hex << addr << ") : 0x" << (length==4?*(uint32_t*)data:length==2?*(uint16_t*)data:(unsigned)*data);
|
||||
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
||||
return false;
|
||||
}
|
||||
@ -575,10 +469,7 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
tlm_dmi_ext dmi_data;
|
||||
if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
|
||||
if (dmi_data.is_read_allowed())
|
||||
read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||
if (dbus->get_direct_mem_ptr(gp, dmi_data)) {
|
||||
if (dmi_data.is_write_allowed())
|
||||
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||
@ -589,43 +480,25 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
}
|
||||
|
||||
bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||
auto lut_entry = read_lut.getEntry(addr);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
||||
addr + length <= lut_entry.get_end_address() + 1) {
|
||||
auto offset = addr - lut_entry.get_start_address();
|
||||
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||
return true;
|
||||
} else {
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
gp.set_data_ptr(data);
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
return initiator->transport_dbg(gp) == length;
|
||||
}
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
gp.set_data_ptr(data);
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
return dbus->transport_dbg(gp) == length;
|
||||
}
|
||||
|
||||
bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||
auto lut_entry = write_lut.getEntry(addr);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
||||
addr + length <= lut_entry.get_end_address() + 1) {
|
||||
auto offset = addr - lut_entry.get_start_address();
|
||||
std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
|
||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||
return true;
|
||||
} else {
|
||||
write_buf.resize(length);
|
||||
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_WRITE_COMMAND);
|
||||
gp.set_address(addr);
|
||||
gp.set_data_ptr(write_buf.data());
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
return initiator->transport_dbg(gp) == length;
|
||||
}
|
||||
write_buf.resize(length);
|
||||
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_WRITE_COMMAND);
|
||||
gp.set_address(addr);
|
||||
gp.set_data_ptr(write_buf.data());
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
return dbus->transport_dbg(gp) == length;
|
||||
}
|
||||
} /* namespace SiFive */
|
||||
} /* namespace tgfs */
|
||||
} /* namespace sysc */
|
||||
|
@ -40,8 +40,10 @@
|
||||
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
|
||||
#ifdef CWR_SYSTEMC
|
||||
#include <scmlinc/scml_property.h>
|
||||
#define SOCKET_WIDTH 32
|
||||
#else
|
||||
#include <cci_configuration>
|
||||
#define SOCKET_WIDTH scc::LT
|
||||
#endif
|
||||
#include <tlm>
|
||||
#include <tlm_utils/tlm_quantumkeeper.h>
|
||||
@ -69,11 +71,13 @@ struct core_trace;
|
||||
|
||||
class core_complex : public sc_core::sc_module, public scc::traceable {
|
||||
public:
|
||||
tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> ibus{"ibus"};
|
||||
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> dbus{"dbus"};
|
||||
|
||||
sc_core::sc_in<bool> rst_i{"rst_i"};
|
||||
|
||||
sc_core::sc_in<bool> global_irq_i{"global_irq_i"};
|
||||
sc_core::sc_in<bool> ext_irq_i{"ext_irq_i"};
|
||||
|
||||
sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"};
|
||||
|
||||
@ -84,7 +88,7 @@ public:
|
||||
#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;
|
||||
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o{"mtime_o"};
|
||||
|
||||
cci::cci_param<std::string> elf_file{"elf_file", ""};
|
||||
|
||||
@ -140,6 +144,8 @@ public:
|
||||
, gdb_server_port{"gdb_server_port", 0}
|
||||
, dump_ir{"dump_ir", false}
|
||||
, mhartid{"mhartid", 0}
|
||||
, plugins{"plugins", ""}
|
||||
, fetch_lut(tlm_dmi_ext())
|
||||
, read_lut(tlm_dmi_ext())
|
||||
, write_lut(tlm_dmi_ext())
|
||||
{
|
||||
@ -151,13 +157,16 @@ public:
|
||||
~core_complex();
|
||||
|
||||
inline void sync(uint64_t cycle) {
|
||||
auto time = curr_clk * (cycle - last_sync_cycle);
|
||||
quantum_keeper.inc(time);
|
||||
auto core_inc = curr_clk * (cycle - last_sync_cycle);
|
||||
auto incr = std::max(core_inc, std::max(ibus_inc, dbus_inc));
|
||||
quantum_keeper.inc(incr);
|
||||
if (quantum_keeper.need_sync()) {
|
||||
wait(quantum_keeper.get_local_time());
|
||||
quantum_keeper.reset();
|
||||
}
|
||||
last_sync_cycle = cycle;
|
||||
ibus_inc = sc_core::SC_ZERO_TIME;
|
||||
dbus_inc = sc_core::SC_ZERO_TIME;
|
||||
}
|
||||
|
||||
bool read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch);
|
||||
@ -181,13 +190,15 @@ protected:
|
||||
void rst_cb();
|
||||
void sw_irq_cb();
|
||||
void timer_irq_cb();
|
||||
void global_irq_cb();
|
||||
void ext_irq_cb();
|
||||
void local_irq_cb();
|
||||
uint64_t last_sync_cycle = 0;
|
||||
util::range_lut<tlm_dmi_ext> read_lut, write_lut;
|
||||
util::range_lut<tlm_dmi_ext> fetch_lut, read_lut, write_lut;
|
||||
tlm_utils::tlm_quantumkeeper quantum_keeper;
|
||||
std::vector<uint8_t> write_buf;
|
||||
core_wrapper* cpu{nullptr};
|
||||
sc_core::sc_signal<sc_core::sc_time> curr_clk;
|
||||
sc_core::sc_time ibus_inc, dbus_inc;
|
||||
core_trace* trc{nullptr};
|
||||
std::unique_ptr<scc::tick2time> t2t;
|
||||
private:
|
||||
@ -195,7 +206,7 @@ private:
|
||||
std::vector<iss::vm_plugin *> plugin_list;
|
||||
|
||||
};
|
||||
} /* namespace SiFive */
|
||||
} /* namespace tgfs */
|
||||
} /* namespace sysc */
|
||||
|
||||
#endif /* _SYSC_CORE_COMPLEX_H_ */
|
88
src/sysc/iss_factory.h
Normal file
88
src/sysc/iss_factory.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _ISS_FACTORY_H_
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
#include <iss/iss.h>
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace sysc {
|
||||
|
||||
using sc_cpu_ptr = std::unique_ptr<sc_core_adapter_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
class iss_factory {
|
||||
public:
|
||||
using base_t = std::tuple<sc_cpu_ptr, vm_ptr>;
|
||||
using create_fn = std::function<base_t(unsigned, void*) >;
|
||||
using registry_t = std::unordered_map<std::string, create_fn> ;
|
||||
|
||||
iss_factory() = default;
|
||||
iss_factory(const iss_factory &) = delete;
|
||||
iss_factory & operator=(const iss_factory &) = delete;
|
||||
|
||||
static iss_factory & instance() { static iss_factory bf; return bf; }
|
||||
|
||||
bool register_creator(const std::string & className, create_fn const& fn) {
|
||||
registry[className] = fn;
|
||||
return true;
|
||||
}
|
||||
|
||||
base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
|
||||
registry_t::const_iterator regEntry = registry.find(className);
|
||||
if (regEntry != registry.end())
|
||||
return regEntry->second(gdb_port, init_data);
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
std::vector<std::string> get_names() {
|
||||
std::vector<std::string> keys{registry.size()};
|
||||
std::transform(std::begin(registry), std::end(registry), std::begin(keys), [](std::pair<std::string, create_fn> const& p){
|
||||
return p.first;
|
||||
});
|
||||
return keys;
|
||||
}
|
||||
private:
|
||||
registry_t registry;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _ISS_FACTORY_H_ */
|
74
src/sysc/register_tgc_c.cpp
Normal file
74
src/sysc/register_tgc_c.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2023 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_factory.h"
|
||||
#include <iss/arch/tgc_c.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
#include "sc_core_adapter.h"
|
||||
#include "core_complex.h"
|
||||
#include <array>
|
||||
|
||||
namespace iss {
|
||||
namespace interp {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#if defined(WITH_TCC)
|
||||
namespace tcc {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
|
||||
})
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
151
src/sysc/sc_core_adapter.h
Normal file
151
src/sysc/sc_core_adapter.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* sc_core_adapter.h
|
||||
*
|
||||
* Created on: Jul 5, 2023
|
||||
* Author: eyck
|
||||
*/
|
||||
|
||||
#ifndef _SYSC_SC_CORE_ADAPTER_H_
|
||||
#define _SYSC_SC_CORE_ADAPTER_H_
|
||||
|
||||
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace sysc {
|
||||
template<typename PLAT>
|
||||
class sc_core_adapter : public PLAT, public sc_core_adapter_if {
|
||||
public:
|
||||
using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t;
|
||||
using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
|
||||
using heart_state_t = typename PLAT::hart_state_type;
|
||||
sc_core_adapter(sysc::tgfs::core_complex *owner)
|
||||
: owner(owner) { }
|
||||
|
||||
iss::arch_if* get_arch_if() override { return this;}
|
||||
|
||||
void set_mhartid(unsigned id) override { PLAT::set_mhartid(id); }
|
||||
|
||||
uint32_t get_mode() override { return this->reg.PRIV; }
|
||||
|
||||
void set_interrupt_execution(bool v) override { this->interrupt_sim = v?1:0; }
|
||||
|
||||
bool get_interrupt_execution() override { return this->interrupt_sim; }
|
||||
|
||||
uint64_t get_state() override { return this->state.mstatus.backing.val; }
|
||||
|
||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||
if (p == iss::arch_if::ISTART)
|
||||
owner->sync(this->instr_if.get_total_cycles());
|
||||
}
|
||||
|
||||
iss::sync_type needed_sync() const override { return iss::PRE_SYNC; }
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
static constexpr std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
if (!owner->disass_output(pc, instr)) {
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
|
||||
<< this->reg.icount + this->cycle_offset << "]";
|
||||
SCCDEBUG(owner->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();
|
||||
}
|
||||
};
|
||||
|
||||
iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
|
||||
if (addr.access && iss::access_type::DEBUG)
|
||||
return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||
else {
|
||||
return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? iss::Ok : iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override {
|
||||
if (addr.access && iss::access_type::DEBUG)
|
||||
return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||
else {
|
||||
auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||
// clear MTIP on mtimecmp write
|
||||
if (addr.val == 0x2004000) {
|
||||
reg_t val;
|
||||
this->read_csr(iss::arch::mip, val);
|
||||
if (val & (1ULL << 7)) this->write_csr(iss::arch::mip, val & ~(1ULL << 7));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
iss::status read_csr(unsigned addr, reg_t &val) override {
|
||||
#ifndef CWR_SYSTEMC
|
||||
if((addr==iss::arch::time || addr==iss::arch::timeh) && owner->mtime_o.get_interface(0)){
|
||||
uint64_t time_val;
|
||||
bool ret = owner->mtime_o->nb_peek(time_val);
|
||||
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 ret?iss::Ok:iss::Err;
|
||||
#else
|
||||
if((addr==iss::arch::time || addr==iss::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 iss::Ok;
|
||||
#endif
|
||||
} else {
|
||||
return PLAT::read_csr(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_until(uint64_t flags) override {
|
||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||
while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) {
|
||||
sc_core::wait(wfi_evt);
|
||||
}
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
void local_irq(short id, bool value) override {
|
||||
reg_t mask = 0;
|
||||
switch (id) {
|
||||
case 3: // SW
|
||||
mask = 1 << 3;
|
||||
break;
|
||||
case 7: // timer
|
||||
mask = 1 << 7;
|
||||
break;
|
||||
case 11: // external
|
||||
mask = 1 << 11;
|
||||
break;
|
||||
default:
|
||||
if(id>15) mask = 1 << id;
|
||||
break;
|
||||
}
|
||||
if (value) {
|
||||
this->csr[iss::arch::mip] |= mask;
|
||||
wfi_evt.notify();
|
||||
} else
|
||||
this->csr[iss::arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
sysc::tgfs::core_complex *const owner;
|
||||
sc_core::sc_event wfi_evt;
|
||||
};
|
||||
}
|
||||
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
|
31
src/sysc/sc_core_adapter_if.h
Normal file
31
src/sysc/sc_core_adapter_if.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* sc_core_adapter.h
|
||||
*
|
||||
* Created on: Jul 5, 2023
|
||||
* Author: eyck
|
||||
*/
|
||||
|
||||
#ifndef _SYSC_SC_CORE_ADAPTER_IF_H_
|
||||
#define _SYSC_SC_CORE_ADAPTER_IF_H_
|
||||
|
||||
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include "core_complex.h"
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace sysc {
|
||||
struct sc_core_adapter_if {
|
||||
virtual iss::arch_if* get_arch_if() = 0;
|
||||
virtual void set_mhartid(unsigned) = 0;
|
||||
virtual uint32_t get_mode() = 0;
|
||||
virtual uint64_t get_state() = 0;
|
||||
virtual bool get_interrupt_execution() = 0;
|
||||
virtual void set_interrupt_execution(bool v) = 0;
|
||||
virtual void local_irq(short id, bool value) = 0;
|
||||
virtual ~sc_core_adapter_if() = default;
|
||||
};
|
||||
}
|
||||
#endif /* _SYSC_SC_CORE_ADAPTER_IF_H_ */
|
1
src/vm/interp/.gitignore
vendored
1
src/vm/interp/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/vm_tgc_*.cpp
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iss/arch/tgf_c.h>
|
||||
#include <iss/arch/tgc_c.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
@ -52,7 +52,7 @@ namespace fp_impl {
|
||||
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
|
||||
}
|
||||
|
||||
namespace tgf_c {
|
||||
namespace tgc_c {
|
||||
using namespace ::llvm;
|
||||
using namespace iss::arch;
|
||||
using namespace iss::debugger;
|
||||
@ -111,7 +111,7 @@ protected:
|
||||
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);
|
||||
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
|
||||
}
|
||||
|
||||
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
|
||||
@ -124,7 +124,7 @@ protected:
|
||||
// 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) };
|
||||
enum { LUT_SIZE = 1 << util::bit_count(static_cast<uint64_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint64_t>(EXTR_MASK16)) };
|
||||
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
|
||||
@ -4042,10 +4042,10 @@ private:
|
||||
****************************************************************************/
|
||||
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
|
||||
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
|
||||
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
|
||||
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits<ARCH>::NEXT_PC), 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->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits<ARCH>::ICOUNT), 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);
|
||||
@ -4082,20 +4082,22 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
// 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;
|
||||
// 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 {
|
||||
if(this->core.has_mmu())
|
||||
paddr = this->core.virt2phys(pc);
|
||||
//TODO: re-add page handling
|
||||
// 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;
|
||||
@ -4109,7 +4111,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
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));
|
||||
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::NEXT_PC), 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) {
|
||||
@ -4133,31 +4135,53 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||
|
||||
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);
|
||||
auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::TRAP_STATE), 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->adj_to64(this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::PC), 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);
|
||||
auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::NEXT_PC), 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);
|
||||
auto *v = this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::TRAP_STATE), 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 tgf_c
|
||||
} // namespace tgc_c
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::tgf_c>(arch::tgf_c *core, unsigned short port, bool dump) {
|
||||
auto ret = new tgf_c::vm_impl<arch::tgf_c>(*core, dump);
|
||||
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
|
||||
auto ret = new tgc_c::vm_impl<arch::tgc_c>(*core, dump);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||
return std::unique_ptr<vm_if>(ret);
|
||||
}
|
||||
} // namespace llvm
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("tgc_c|m_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
|
||||
auto* vm = new llvm::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("tgc_c|mu_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::tgc_c>();
|
||||
auto* vm = new llvm::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
3252
src/vm/tcc/vm_tgc_c.cpp
Normal file
3252
src/vm/tcc/vm_tgc_c.cpp
Normal file
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
Reference in New Issue
Block a user