Compare commits
	
		
			1 Commits
		
	
	
		
			2095ac985b
			...
			feature/is
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a6c7b1427e | 
							
								
								
									
										164
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								CMakeLists.txt
									
									
									
									
									
								
							@@ -1,70 +1,80 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.12)
 | 
					cmake_minimum_required(VERSION 3.12)
 | 
				
			||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
 | 
					 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
project(dbt-rise-tgc VERSION 1.0.0)
 | 
					project(dbt-rise-tgc VERSION 1.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(GNUInstallDirs)
 | 
					include(GNUInstallDirs)
 | 
				
			||||||
include(flink)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
find_package(elfio QUIET)
 | 
					find_package(elfio QUIET)
 | 
				
			||||||
 | 
					find_package(Boost COMPONENTS coroutine)
 | 
				
			||||||
find_package(jsoncpp)
 | 
					find_package(jsoncpp)
 | 
				
			||||||
find_package(Boost COMPONENTS coroutine REQUIRED)
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_subdirectory(softfloat)
 | 
					add_subdirectory(softfloat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(LIB_SOURCES 
 | 
					set(LIB_SOURCES 
 | 
				
			||||||
    src/iss/plugin/instruction_count.cpp
 | 
					    src/iss/plugin/instruction_count.cpp
 | 
				
			||||||
	src/iss/arch/tgc5c.cpp
 | 
						src/iss/arch/tgc_c.cpp
 | 
				
			||||||
	src/vm/interp/vm_tgc5c.cpp
 | 
						src/vm/interp/vm_tgc_c.cpp
 | 
				
			||||||
	src/vm/fp_functions.cpp
 | 
						src/vm/fp_functions.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
if(WITH_TCC)
 | 
					 | 
				
			||||||
	list(APPEND LIB_SOURCES
 | 
					 | 
				
			||||||
	   src/vm/tcc/vm_tgc5c.cpp
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
if(WITH_LLVM)
 | 
					 | 
				
			||||||
	list(APPEND LIB_SOURCES
 | 
					 | 
				
			||||||
		src/vm/llvm/vm_tgc5c.cpp
 | 
					 | 
				
			||||||
		src/vm/llvm/fp_impl.cpp
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# library files
 | 
					# library files
 | 
				
			||||||
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
 | 
					if(TARGET ${CORE_NAME}_cpp)
 | 
				
			||||||
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
 | 
					    list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
 | 
				
			||||||
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
 | 
					else()
 | 
				
			||||||
foreach(FILEPATH ${GEN_ISS_SOURCES})
 | 
					    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)
 | 
					        get_filename_component(CORE ${FILEPATH} NAME_WE)
 | 
				
			||||||
        string(TOUPPER ${CORE} CORE)
 | 
					        string(TOUPPER ${CORE} CORE)
 | 
				
			||||||
        list(APPEND LIB_DEFINES CORE_${CORE})
 | 
					        list(APPEND LIB_DEFINES CORE_${CORE})
 | 
				
			||||||
endforeach()
 | 
					    endforeach()
 | 
				
			||||||
message(STATUS "Core defines are ${LIB_DEFINES}")
 | 
					    message("Defines are ${LIB_DEFINES}")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
 | 
				
			||||||
 | 
					    list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(WITH_LLVM)
 | 
					if(WITH_LLVM)
 | 
				
			||||||
	FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp)
 | 
						FILE(GLOB LLVM_GEN_SOURCES
 | 
				
			||||||
 | 
						    ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
	list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
 | 
						list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(WITH_TCC)
 | 
					if(WITH_TCC)
 | 
				
			||||||
	FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
 | 
						FILE(GLOB TCC_GEN_SOURCES
 | 
				
			||||||
 | 
						    ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
	list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
 | 
						list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
 | 
					 | 
				
			||||||
    list(APPEND LIB_SOURCES 
 | 
					 | 
				
			||||||
    	src/iss/plugin/cycle_estimate.cpp
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
if(TARGET jsoncpp::jsoncpp)
 | 
					 | 
				
			||||||
    list(APPEND LIB_SOURCES 
 | 
					 | 
				
			||||||
	    src/iss/plugin/instruction_count.cpp
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
# Define the library
 | 
					# Define the library
 | 
				
			||||||
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
 | 
					add_library(${PROJECT_NAME} ${LIB_SOURCES})
 | 
				
			||||||
 | 
					# list code gen dependencies
 | 
				
			||||||
 | 
					if(TARGET ${CORE_NAME}_cpp)
 | 
				
			||||||
 | 
					    add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 | 
					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)
 | 
				
			||||||
@@ -73,32 +83,32 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
 | 
				
			|||||||
endif()
 | 
					endif()
 | 
				
			||||||
target_include_directories(${PROJECT_NAME} PUBLIC src)
 | 
					target_include_directories(${PROJECT_NAME} PUBLIC src)
 | 
				
			||||||
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
 | 
					target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
 | 
				
			||||||
 | 
					target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util Boost::coroutine)
 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
if(NOT (DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND))
 | 
					 | 
				
			||||||
	target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)
 | 
					 | 
				
			||||||
if(TARGET jsoncpp::jsoncpp)
 | 
					if(TARGET jsoncpp::jsoncpp)
 | 
				
			||||||
	target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp)
 | 
						target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp)
 | 
				
			||||||
 | 
					else()
 | 
				
			||||||
 | 
						target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
if(TARGET RapidJSON)
 | 
					if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND BUILD_SHARED_LIBS)
 | 
				
			||||||
 | 
					    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 elfio::elfio)
 | 
				
			||||||
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
 | 
				
			||||||
 | 
					else()
 | 
				
			||||||
 | 
					    message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					if(TARGET lz4::lz4)
 | 
				
			||||||
 | 
					    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
 | 
				
			||||||
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					if(TARGET RapidJSON::RapidJSON)
 | 
				
			||||||
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON::RapidJSON)
 | 
				
			||||||
 | 
					elseif(TARGET RapidJSON)
 | 
				
			||||||
    target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(WITH_LLVM)
 | 
					 | 
				
			||||||
    find_package(LLVM)
 | 
					 | 
				
			||||||
	target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS})
 | 
					 | 
				
			||||||
	target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS})
 | 
					 | 
				
			||||||
	if(BUILD_SHARED_LIBS)
 | 
					 | 
				
			||||||
		target_link_libraries( ${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES})
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
					set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
				
			||||||
  VERSION ${PROJECT_VERSION}
 | 
					  VERSION ${PROJECT_VERSION}
 | 
				
			||||||
@@ -143,16 +153,15 @@ foreach(F IN LISTS TGC_SOURCES)
 | 
				
			|||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
endforeach()
 | 
					endforeach()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if(WITH_LLVM)
 | 
					if(WITH_LLVM)
 | 
				
			||||||
#    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
 | 
					    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
 | 
				
			||||||
#    #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
				
			||||||
#endif()
 | 
					endif()
 | 
				
			||||||
#if(WITH_TCC)
 | 
					if(WITH_TCC)
 | 
				
			||||||
#    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
 | 
					    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
 | 
				
			||||||
#endif()
 | 
					endif()
 | 
				
			||||||
 | 
					# Links the target exe against the libraries
 | 
				
			||||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)
 | 
					target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
 | 
				
			||||||
 | 
					 | 
				
			||||||
if(TARGET Boost::program_options)
 | 
					if(TARGET Boost::program_options)
 | 
				
			||||||
    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
@@ -172,32 +181,15 @@ install(TARGETS tgc-sim
 | 
				
			|||||||
  PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}  # headers for mac (note the different component -> different package)
 | 
					  PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}  # headers for mac (note the different component -> different package)
 | 
				
			||||||
  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}             # headers
 | 
					  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()
 | 
					 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
if(TARGET scc-sysc)
 | 
					if(TARGET scc-sysc)
 | 
				
			||||||
	project(dbt-rise-tgc_sc VERSION 1.0.0)
 | 
						project(dbt-rise-tgc_sc VERSION 1.0.0)
 | 
				
			||||||
	set(LIB_SOURCES 
 | 
					    add_library(${PROJECT_NAME} 
 | 
				
			||||||
    	src/sysc/core_complex.cpp
 | 
					    	src/sysc/core_complex.cpp
 | 
				
			||||||
    	src/sysc/register_tgc_c.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} PUBLIC WITH_SYSTEMC)
 | 
				
			||||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
					    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
				
			||||||
    foreach(F IN LISTS TGC_SOURCES)
 | 
					    foreach(F IN LISTS TGC_SOURCES)
 | 
				
			||||||
@@ -208,9 +200,9 @@ if(TARGET scc-sysc)
 | 
				
			|||||||
        endif()
 | 
					        endif()
 | 
				
			||||||
    endforeach()
 | 
					    endforeach()
 | 
				
			||||||
    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
 | 
				
			||||||
#    if(WITH_LLVM)
 | 
					    if(WITH_LLVM)
 | 
				
			||||||
#        target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
					        target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
				
			||||||
#    endif()
 | 
					    endif()
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
 | 
						set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
 | 
				
			||||||
    set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
					    set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,51 +15,59 @@ RV32I:
 | 
				
			|||||||
  - JAL:
 | 
					  - JAL:
 | 
				
			||||||
    encoding: 0b00000000000000000000000001101111
 | 
					    encoding: 0b00000000000000000000000001101111
 | 
				
			||||||
    mask: 0b00000000000000000000000001111111
 | 
					    mask: 0b00000000000000000000000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
  - JALR:
 | 
					  - JALR:
 | 
				
			||||||
    encoding: 0b00000000000000000000000001100111
 | 
					    encoding: 0b00000000000000000000000001100111
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
  - BEQ:
 | 
					  - BEQ:
 | 
				
			||||||
    encoding: 0b00000000000000000000000001100011
 | 
					    encoding: 0b00000000000000000000000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - BNE:
 | 
					  - BNE:
 | 
				
			||||||
    encoding: 0b00000000000000000001000001100011
 | 
					    encoding: 0b00000000000000000001000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - BLT:
 | 
					  - BLT:
 | 
				
			||||||
    encoding: 0b00000000000000000100000001100011
 | 
					    encoding: 0b00000000000000000100000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - BGE:
 | 
					  - BGE:
 | 
				
			||||||
    encoding: 0b00000000000000000101000001100011
 | 
					    encoding: 0b00000000000000000101000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - BLTU:
 | 
					  - BLTU:
 | 
				
			||||||
    encoding: 0b00000000000000000110000001100011
 | 
					    encoding: 0b00000000000000000110000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - BGEU:
 | 
					  - BGEU:
 | 
				
			||||||
    encoding: 0b00000000000000000111000001100011
 | 
					    encoding: 0b00000000000000000111000001100011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - LB:
 | 
					  - LB:
 | 
				
			||||||
    encoding: 0b00000000000000000000000000000011
 | 
					    encoding: 0b00000000000000000000000000000011
 | 
				
			||||||
    mask: 0b00000000000000000111000001111111
 | 
					    mask: 0b00000000000000000111000001111111
 | 
				
			||||||
@@ -231,12 +239,14 @@ RV32I:
 | 
				
			|||||||
  - ECALL:
 | 
					  - ECALL:
 | 
				
			||||||
    encoding: 0b00000000000000000000000001110011
 | 
					    encoding: 0b00000000000000000000000001110011
 | 
				
			||||||
    mask: 0b11111111111111111111111111111111
 | 
					    mask: 0b11111111111111111111111111111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   false
 | 
					    branch:   false
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
  - EBREAK:
 | 
					  - EBREAK:
 | 
				
			||||||
    encoding: 0b00000000000100000000000001110011
 | 
					    encoding: 0b00000000000100000000000001110011
 | 
				
			||||||
    mask: 0b11111111111111111111111111111111
 | 
					    mask: 0b11111111111111111111111111111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   32
 | 
					    size:   32
 | 
				
			||||||
    branch:   false
 | 
					    branch:   false
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
@@ -381,6 +391,7 @@ RV32IC:
 | 
				
			|||||||
  - CJAL:
 | 
					  - CJAL:
 | 
				
			||||||
    encoding: 0b0010000000000001
 | 
					    encoding: 0b0010000000000001
 | 
				
			||||||
    mask: 0b1110000000000011
 | 
					    mask: 0b1110000000000011
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
@@ -447,21 +458,24 @@ RV32IC:
 | 
				
			|||||||
  - CJ:
 | 
					  - CJ:
 | 
				
			||||||
    encoding: 0b1010000000000001
 | 
					    encoding: 0b1010000000000001
 | 
				
			||||||
    mask: 0b1110000000000011
 | 
					    mask: 0b1110000000000011
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
  - CBEQZ:
 | 
					  - CBEQZ:
 | 
				
			||||||
    encoding: 0b1100000000000001
 | 
					    encoding: 0b1100000000000001
 | 
				
			||||||
    mask: 0b1110000000000011
 | 
					    mask: 0b1110000000000011
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - CBNEZ:
 | 
					  - CBNEZ:
 | 
				
			||||||
    encoding: 0b1110000000000001
 | 
					    encoding: 0b1110000000000001
 | 
				
			||||||
    mask: 0b1110000000000011
 | 
					    mask: 0b1110000000000011
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont], [name:cond]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   [1,1]
 | 
				
			||||||
  - CSLLI:
 | 
					  - CSLLI:
 | 
				
			||||||
    encoding: 0b0000000000000010
 | 
					    encoding: 0b0000000000000010
 | 
				
			||||||
    mask: 0b1111000000000011
 | 
					    mask: 0b1111000000000011
 | 
				
			||||||
@@ -483,6 +497,7 @@ RV32IC:
 | 
				
			|||||||
  - CJR:
 | 
					  - CJR:
 | 
				
			||||||
    encoding: 0b1000000000000010
 | 
					    encoding: 0b1000000000000010
 | 
				
			||||||
    mask: 0b1111000001111111
 | 
					    mask: 0b1111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
@@ -495,12 +510,14 @@ RV32IC:
 | 
				
			|||||||
  - CJALR:
 | 
					  - CJALR:
 | 
				
			||||||
    encoding: 0b1001000000000010
 | 
					    encoding: 0b1001000000000010
 | 
				
			||||||
    mask: 0b1111000001111111
 | 
					    mask: 0b1111000001111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   true
 | 
					    branch:   true
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
  - CEBREAK:
 | 
					  - CEBREAK:
 | 
				
			||||||
    encoding: 0b1001000000000010
 | 
					    encoding: 0b1001000000000010
 | 
				
			||||||
    mask: 0b1111111111111111
 | 
					    mask: 0b1111111111111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   false
 | 
					    branch:   false
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
@@ -513,6 +530,7 @@ RV32IC:
 | 
				
			|||||||
  - DII:
 | 
					  - DII:
 | 
				
			||||||
    encoding: 0b0000000000000000
 | 
					    encoding: 0b0000000000000000
 | 
				
			||||||
    mask: 0b1111111111111111
 | 
					    mask: 0b1111111111111111
 | 
				
			||||||
 | 
					    attributes: [[name:no_cont]]
 | 
				
			||||||
    size:   16
 | 
					    size:   16
 | 
				
			||||||
    branch:   false
 | 
					    branch:   false
 | 
				
			||||||
    delay:   1
 | 
					    delay:   1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,35 +0,0 @@
 | 
				
			|||||||
# 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()
 | 
					 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
import "ISA/RVI.core_desc"
 | 
					import "ISA/RV32I.core_desc"
 | 
				
			||||||
import "ISA/RVM.core_desc"
 | 
					import "ISA/RVM.core_desc"
 | 
				
			||||||
import "ISA/RVC.core_desc"
 | 
					import "ISA/RVC.core_desc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Core TGC5C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
 | 
					Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
 | 
				
			||||||
    architectural_state {
 | 
					    architectural_state {
 | 
				
			||||||
        XLEN=32;
 | 
					        XLEN=32;
 | 
				
			||||||
        // definitions for the architecture wrapper
 | 
					        // definitions for the architecture wrapper
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,7 @@ uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
 | 
				
			|||||||
	return reinterpret_cast<uint8_t*>(®);
 | 
						return reinterpret_cast<uint8_t*>(®);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &addr) {
 | 
					${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
 | 
				
			||||||
    return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
 | 
					    return phys_addr_t(pc); // change logical address to physical address
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ def byteSize(int size){
 | 
				
			|||||||
    return 128;
 | 
					    return 128;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
def getCString(def val){
 | 
					def getCString(def val){
 | 
				
			||||||
    return val.toString()+'ULL'
 | 
					    return val.toString()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
%>
 | 
					%>
 | 
				
			||||||
#ifndef _${coreDef.name.toUpperCase()}_H_
 | 
					#ifndef _${coreDef.name.toUpperCase()}_H_
 | 
				
			||||||
@@ -76,10 +76,10 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
 | 
				
			|||||||
    constexpr static char const* const core_type = "${coreDef.name}";
 | 
					    constexpr static char const* const core_type = "${coreDef.name}";
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    static constexpr std::array<const char*, ${registers.size}> reg_names{
 | 
					    static constexpr std::array<const char*, ${registers.size}> reg_names{
 | 
				
			||||||
        {"${registers.collect{it.name.toLowerCase()}.join('", "')}"}};
 | 
					        {"${registers.collect{it.name}.join('", "')}"}};
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    static constexpr std::array<const char*, ${registers.size}> reg_aliases{
 | 
					    static constexpr std::array<const char*, ${registers.size}> reg_aliases{
 | 
				
			||||||
        {"${registers.collect{it.alias.toLowerCase()}.join('", "')}"}};
 | 
					        {"${registers.collect{it.alias}.join('", "')}"}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
 | 
					    enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -137,6 +137,14 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    inline uint64_t stop_code() { 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 phys_addr_t virt2phys(const iss::addr_t& addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
 | 
					    virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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()}>>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,74 +0,0 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					 | 
				
			||||||
 * 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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -43,7 +43,6 @@ def nativeTypeSize(int size){
 | 
				
			|||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <boost/coroutine2/all.hpp>
 | 
					#include <boost/coroutine2/all.hpp>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <exception>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef FMT_HEADER_ONLY
 | 
					#ifndef FMT_HEADER_ONLY
 | 
				
			||||||
#define FMT_HEADER_ONLY
 | 
					#define FMT_HEADER_ONLY
 | 
				
			||||||
@@ -60,10 +59,6 @@ using namespace iss::arch;
 | 
				
			|||||||
using namespace iss::debugger;
 | 
					using namespace iss::debugger;
 | 
				
			||||||
using namespace std::placeholders;
 | 
					using namespace std::placeholders;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct memory_access_exception : public std::exception{
 | 
					 | 
				
			||||||
    memory_access_exception(){}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
 | 
					template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    using traits = arch::traits<ARCH>;
 | 
					    using traits = arch::traits<ARCH>;
 | 
				
			||||||
@@ -96,9 +91,30 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
 | 
					    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;
 | 
					    virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // some compile time constants
 | 
					    // 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(static_cast<uint32_t>(EXTR_MASK32)),
 | 
				
			||||||
 | 
					        LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(EXTR_MASK16))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::array<compile_func, LUT_SIZE> lut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
 | 
				
			||||||
 | 
					    std::array<compile_func, LUT_SIZE> lut_11;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct instruction_pattern {
 | 
				
			||||||
 | 
					        uint32_t value;
 | 
				
			||||||
 | 
					        uint32_t mask;
 | 
				
			||||||
 | 
					        typename arch::traits<ARCH>::opcode_e id;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::array<std::vector<instruction_pattern>, 4> qlut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline void raise(uint16_t trap_id, uint16_t cause){
 | 
					    inline void raise(uint16_t trap_id, uint16_t cause){
 | 
				
			||||||
        auto trap_val =  0x80ULL << 24 | (cause << 16) | trap_id;
 | 
					        auto trap_val =  0x80ULL << 24 | (cause << 16) | trap_id;
 | 
				
			||||||
@@ -142,96 +158,30 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        typename arch::traits<ARCH>::opcode_e op;
 | 
					        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){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
 | 
				
			||||||
    const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
					         /* 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}},<%}%>
 | 
					        {${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){
 | 
					    iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
 | 
				
			||||||
        if(this->core.has_mmu()) {
 | 
					        auto phys_pc = this->core.v2p(pc);
 | 
				
			||||||
            auto phys_pc = this->core.virt2phys(pc);
 | 
					        //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
//            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 (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
 | 
					        //    if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
 | 
				
			||||||
//                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;
 | 
				
			||||||
//                    if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok)
 | 
					        //} else {
 | 
				
			||||||
//                        return iss::Err;
 | 
					            if (this->core.read(phys_pc, 4, data) != 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;
 | 
					        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) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
@@ -258,11 +208,16 @@ constexpr size_t bit_count(uint32_t u) {
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    unsigned id=0;
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    for (auto instr : instr_descr) {
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					        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);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
					inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
				
			||||||
@@ -273,6 +228,14 @@ 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;
 | 
					    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>
 | 
					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){
 | 
					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=start;
 | 
				
			||||||
@@ -294,11 +257,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (is_jump_to_self_enabled(cond) &&
 | 
					            if (is_jump_to_self_enabled(cond) &&
 | 
				
			||||||
                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
				
			||||||
            auto inst_id = decode_instr(root, instr);
 | 
					            auto inst_id = decode_inst_id(instr);
 | 
				
			||||||
            // pre execution stuff
 | 
					            // pre execution stuff
 | 
				
			||||||
             this->core.reg.last_branch = 0;
 | 
					             this->core.reg.last_branch = 0;
 | 
				
			||||||
            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
					            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
				
			||||||
            try{
 | 
					 | 
				
			||||||
            switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
 | 
					            switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
 | 
				
			||||||
            case arch::traits<ARCH>::opcode_e::${instr.name}: {
 | 
					            case arch::traits<ARCH>::opcode_e::${instr.name}: {
 | 
				
			||||||
                <%instr.fields.eachLine{%>${it}
 | 
					                <%instr.fields.eachLine{%>${it}
 | 
				
			||||||
@@ -314,14 +276,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
                *NEXT_PC = *PC + ${instr.length/8};
 | 
					                *NEXT_PC = *PC + ${instr.length/8};
 | 
				
			||||||
                // execute instruction<%instr.behavior.eachLine{%>
 | 
					                // execute instruction<%instr.behavior.eachLine{%>
 | 
				
			||||||
                ${it}<%}%>
 | 
					                ${it}<%}%>
 | 
				
			||||||
                    break;
 | 
					                TRAP_${instr.name}:break;
 | 
				
			||||||
            }// @suppress("No break at end of case")<%}%>
 | 
					            }// @suppress("No break at end of case")<%}%>
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
                *NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
 | 
					                *NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
 | 
				
			||||||
                raise(0,  2);
 | 
					                raise(0,  2);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }catch(memory_access_exception& e){}
 | 
					 | 
				
			||||||
            // post execution stuff
 | 
					            // post execution stuff
 | 
				
			||||||
            process_spawn_blocks();
 | 
					            process_spawn_blocks();
 | 
				
			||||||
            if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
 | 
					            if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
 | 
				
			||||||
@@ -343,7 +304,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
    return pc;
 | 
					    return pc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ${coreDef.name.toLowerCase()}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -359,7 +320,7 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					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>{
 | 
					        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* 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);
 | 
							    auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
@@ -375,3 +336,8 @@ volatile std::array<bool, 2> dummy = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_${coreDef.name.toLowerCase()}_interp_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								gen_input/templates/llvm/CORENAME_cyles.txt.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								gen_input/templates/llvm/CORENAME_cyles.txt.gtl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{ 
 | 
				
			||||||
 | 
						"${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}
 | 
				
			||||||
 | 
							}<%}%>
 | 
				
			||||||
 | 
						]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										223
									
								
								gen_input/templates/llvm/incl-CORENAME.h.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								gen_input/templates/llvm/incl-CORENAME.h.gtl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
				
			|||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * 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_ */
 | 
				
			||||||
							
								
								
									
										107
									
								
								gen_input/templates/llvm/src-CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								gen_input/templates/llvm/src-CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,9 +30,10 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *******************************************************************************/
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
 | 
					 | 
				
			||||||
#include <iss/debugger/gdb_session.h>
 | 
					#include <iss/debugger/gdb_session.h>
 | 
				
			||||||
#include <iss/debugger/server.h>
 | 
					#include <iss/debugger/server.h>
 | 
				
			||||||
 | 
					#include <iss/arch/${coreDef.name.toLowerCase()}.h>
 | 
				
			||||||
 | 
					#include <iss/arch/riscv_hart_m_p.h>
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/iss.h>
 | 
				
			||||||
#include <iss/llvm/vm_base.h>
 | 
					#include <iss/llvm/vm_base.h>
 | 
				
			||||||
#include <util/logging.h>
 | 
					#include <util/logging.h>
 | 
				
			||||||
@@ -58,7 +59,6 @@ using namespace iss::debugger;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> class vm_impl : public iss::llvm::vm_base<ARCH> {
 | 
					template <typename ARCH> class vm_impl : public iss::llvm::vm_base<ARCH> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    using traits = arch::traits<ARCH>;
 | 
					 | 
				
			||||||
    using super = typename iss::llvm::vm_base<ARCH>;
 | 
					    using super = typename iss::llvm::vm_base<ARCH>;
 | 
				
			||||||
    using virt_addr_t = typename super::virt_addr_t;
 | 
					    using virt_addr_t = typename super::virt_addr_t;
 | 
				
			||||||
    using phys_addr_t = typename super::phys_addr_t;
 | 
					    using phys_addr_t = typename super::phys_addr_t;
 | 
				
			||||||
@@ -81,7 +81,7 @@ public:
 | 
				
			|||||||
protected:
 | 
					protected:
 | 
				
			||||||
    using vm_base<ARCH>::get_reg_ptr;
 | 
					    using vm_base<ARCH>::get_reg_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline const char *name(size_t index){return traits::reg_aliases.at(index);}
 | 
					    inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename T> inline ConstantInt *size(T type) {
 | 
					    template <typename T> inline ConstantInt *size(T type) {
 | 
				
			||||||
        return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
 | 
					        return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
 | 
				
			||||||
@@ -89,7 +89,7 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void setup_module(Module* m) override {
 | 
					    void setup_module(Module* m) override {
 | 
				
			||||||
        super::setup_module(m);
 | 
					        super::setup_module(m);
 | 
				
			||||||
        iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN);
 | 
					        iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
 | 
					    inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
 | 
				
			||||||
@@ -111,150 +111,116 @@ protected:
 | 
				
			|||||||
    void gen_trap_check(BasicBlock *bb);
 | 
					    void gen_trap_check(BasicBlock *bb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
 | 
					    inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
 | 
				
			||||||
        return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
 | 
					        return this->builder.CreateLoad(get_reg_ptr(i), false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
 | 
					    inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
 | 
				
			||||||
        Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits::XLEN, pc.val),
 | 
					        Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
 | 
				
			||||||
                                                           this->get_type(traits::XLEN));
 | 
					                                                           this->get_type(traits<ARCH>::XLEN));
 | 
				
			||||||
        this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
 | 
					        this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // some compile time constants
 | 
					    // 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) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using this_class = vm_impl<ARCH>;
 | 
					    using this_class = vm_impl<ARCH>;
 | 
				
			||||||
    using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
 | 
					    using compile_func = std::tuple<continuation_e, BasicBlock *> (this_class::*)(virt_addr_t &pc,
 | 
				
			||||||
                                                                                  code_word_t instr,
 | 
					                                                                                  code_word_t instr,
 | 
				
			||||||
                                                                                  BasicBlock *bb);
 | 
					                                                                                  BasicBlock *bb);
 | 
				
			||||||
    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
					    std::array<compile_func, LUT_SIZE> lut;
 | 
				
			||||||
    inline S sext(U from) {
 | 
					
 | 
				
			||||||
        auto mask = (1ULL<<W) - 1;
 | 
					    std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
 | 
				
			||||||
        auto sign_mask = 1ULL<<(W-1);
 | 
					    std::array<compile_func, LUT_SIZE> lut_11;
 | 
				
			||||||
        return (from & mask) | ((from & sign_mask) ? ~mask : 0);
 | 
					
 | 
				
			||||||
 | 
						std::array<compile_func *, 4> qlut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
 | 
				
			||||||
 | 
					                         compile_func f) {
 | 
				
			||||||
 | 
					        if (pos < 0) {
 | 
				
			||||||
 | 
					            lut[idx] = f;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            auto bitmask = 1UL << pos;
 | 
				
			||||||
 | 
					            if ((mask & bitmask) == 0) {
 | 
				
			||||||
 | 
					                expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if ((valid & bitmask) == 0) {
 | 
				
			||||||
 | 
					                    expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
 | 
				
			||||||
 | 
					                    expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    auto new_val = idx << 1;
 | 
				
			||||||
 | 
					                    if ((value & bitmask) != 0) new_val++;
 | 
				
			||||||
 | 
					                    expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
 | 
				
			||||||
 | 
					        if (pos >= 0) {
 | 
				
			||||||
 | 
					            auto bitmask = 1UL << pos;
 | 
				
			||||||
 | 
					            if ((mask & bitmask) == 0) {
 | 
				
			||||||
 | 
					                lut_val = extract_fields(pos - 1, val, mask, lut_val);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                auto new_val = lut_val << 1;
 | 
				
			||||||
 | 
					                if ((val & bitmask) != 0) new_val++;
 | 
				
			||||||
 | 
					                lut_val = extract_fields(pos - 1, val, mask, new_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return lut_val;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        compile_func op;
 | 
					        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){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
					         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
				
			||||||
        /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
 | 
					        /* instruction ${instr.instruction.name} */
 | 
				
			||||||
        {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
					        {${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
				
			||||||
    }};
 | 
					    }};
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
 | 
					    /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
 | 
				
			||||||
    /* instruction ${idx}: ${instr.name} */
 | 
					    /* instruction ${idx}: ${instr.name} */
 | 
				
			||||||
    std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
 | 
					    std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){<%instr.code.eachLine{%>
 | 
				
			||||||
        bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
 | 
					 | 
				
			||||||
        this->gen_sync(PRE_SYNC,${idx});
 | 
					 | 
				
			||||||
        uint64_t PC = pc.val;
 | 
					 | 
				
			||||||
        <%instr.fields.eachLine{%>${it}
 | 
					 | 
				
			||||||
        <%}%>if(this->disass_enabled){
 | 
					 | 
				
			||||||
            /* generate console output when executing the command */<%instr.disass.eachLine{%>
 | 
					 | 
				
			||||||
    	${it}<%}%>
 | 
					    	${it}<%}%>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        auto cur_pc_val = this->gen_const(32,pc.val);
 | 
					 | 
				
			||||||
        pc=pc+ ${instr.length/8};
 | 
					 | 
				
			||||||
        this->gen_set_pc(pc, traits::NEXT_PC);
 | 
					 | 
				
			||||||
        <%instr.behavior.eachLine{%>${it}
 | 
					 | 
				
			||||||
        <%}%>
 | 
					 | 
				
			||||||
        this->gen_trap_check(bb);
 | 
					 | 
				
			||||||
    	this->gen_sync(POST_SYNC, ${idx});
 | 
					 | 
				
			||||||
        this->builder.CreateBr(bb);
 | 
					 | 
				
			||||||
    	return returnValue;        
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    <%}%>
 | 
					    <%}%>
 | 
				
			||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * end opcode definitions
 | 
					     * end opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
 | 
					    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->gen_sync(iss::PRE_SYNC, instr_descr.size());
 | 
				
			||||||
        this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true),
 | 
					        this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
 | 
				
			||||||
                                   get_reg_ptr(traits::PC), true);
 | 
					                                   get_reg_ptr(traits<ARCH>::PC), true);
 | 
				
			||||||
        this->builder.CreateStore(
 | 
					        this->builder.CreateStore(
 | 
				
			||||||
            this->builder.CreateAdd(this->builder.CreateLoad(this->get_typeptr(traits::ICOUNT), get_reg_ptr(traits::ICOUNT), true),
 | 
					            this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
 | 
				
			||||||
                                     this->gen_const(64U, 1)),
 | 
					                                     this->gen_const(64U, 1)),
 | 
				
			||||||
            get_reg_ptr(traits::ICOUNT), true);
 | 
					            get_reg_ptr(traits<ARCH>::ICOUNT), true);
 | 
				
			||||||
        pc = pc + ((instr & 3) == 3 ? 4 : 2);
 | 
					        pc = pc + ((instr & 3) == 3 ? 4 : 2);
 | 
				
			||||||
        this->gen_raise_trap(0, 2);     // illegal instruction trap
 | 
					        this->gen_raise_trap(0, 2);     // illegal instruction trap
 | 
				
			||||||
		this->gen_sync(iss::POST_SYNC, instr_descr.size());
 | 
							this->gen_sync(iss::POST_SYNC, instr_descr.size());
 | 
				
			||||||
        this->gen_trap_check(this->leave_blk);
 | 
					        this->gen_trap_check(this->leave_blk);
 | 
				
			||||||
        return std::make_tuple(BRANCH, nullptr);
 | 
					        return std::make_tuple(BRANCH, nullptr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //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 instr) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
    volatile CODE_WORD x = instr;
 | 
					    volatile CODE_WORD x = insn;
 | 
				
			||||||
    instr = 2 * x;
 | 
					    insn = 2 * x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
					template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			||||||
@@ -262,11 +228,14 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    qlut[0] = lut_00.data();
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    qlut[1] = lut_01.data();
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
@@ -274,50 +243,49 @@ std::tuple<continuation_e, BasicBlock *>
 | 
				
			|||||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) {
 | 
					vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) {
 | 
				
			||||||
    // we fetch at max 4 byte, alignment is 2
 | 
					    // we fetch at max 4 byte, alignment is 2
 | 
				
			||||||
    enum {TRAP_ID=1<<16};
 | 
					    enum {TRAP_ID=1<<16};
 | 
				
			||||||
    code_word_t instr = 0;
 | 
					    code_word_t insn = 0;
 | 
				
			||||||
    // const typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
					    const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
 | 
				
			||||||
    phys_addr_t paddr(pc);
 | 
					    phys_addr_t paddr(pc);
 | 
				
			||||||
    auto *const data = (uint8_t *)&instr;
 | 
					    auto *const data = (uint8_t *)&insn;
 | 
				
			||||||
    if(this->core.has_mmu())
 | 
					    paddr = this->core.v2p(pc);
 | 
				
			||||||
        paddr = this->core.virt2phys(pc);
 | 
					    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
    //TODO: re-add page handling
 | 
					        auto res = this->core.read(paddr, 2, data);
 | 
				
			||||||
//    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
					        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
				
			||||||
//        auto res = this->core.read(paddr, 2, data);
 | 
					        if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
 | 
				
			||||||
//        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					            res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
 | 
				
			||||||
//        if ((instr & 0x3) == 0x3) { // this is a 32bit instruction
 | 
					        }
 | 
				
			||||||
//            res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
 | 
					    } else {
 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//    } else {
 | 
					 | 
				
			||||||
        auto res = this->core.read(paddr, 4, data);
 | 
					        auto res = this->core.read(paddr, 4, data);
 | 
				
			||||||
        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
				
			||||||
//    }
 | 
					    }
 | 
				
			||||||
    if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					    if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
				
			||||||
    // curr pc on stack
 | 
					    // curr pc on stack
 | 
				
			||||||
    ++inst_cnt;
 | 
					    ++inst_cnt;
 | 
				
			||||||
    auto f = decode_instr(root, instr);
 | 
					    auto lut_val = extract_fields(insn);
 | 
				
			||||||
 | 
					    auto f = qlut[insn & 0x3][lut_val];
 | 
				
			||||||
    if (f == nullptr) {
 | 
					    if (f == nullptr) {
 | 
				
			||||||
        f = &this_class::illegal_intruction;
 | 
					        f = &this_class::illegal_intruction;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (this->*f)(pc, instr, this_block);
 | 
					    return (this->*f)(pc, insn, this_block);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
 | 
				
			||||||
    this->builder.SetInsertPoint(leave_blk);
 | 
					    this->builder.SetInsertPoint(leave_blk);
 | 
				
			||||||
    this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false));
 | 
					    this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
 | 
				
			||||||
    auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
 | 
					    auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
 | 
				
			||||||
    this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
 | 
					    this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
 | 
				
			||||||
    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
 | 
					    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
 | 
				
			||||||
    std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
 | 
					    std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
 | 
				
			||||||
    this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
 | 
					    this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
 | 
				
			||||||
    auto *PC_val = this->gen_read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN / 8);
 | 
					    auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
 | 
				
			||||||
    this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false);
 | 
					    this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
 | 
				
			||||||
    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
 | 
					    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
 | 
				
			||||||
@@ -327,25 +295,22 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
 | 
				
			||||||
    this->builder.SetInsertPoint(trap_blk);
 | 
					    this->builder.SetInsertPoint(trap_blk);
 | 
				
			||||||
    this->gen_sync(POST_SYNC, -1); //TODO get right InstrId
 | 
					    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(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
 | 
					 | 
				
			||||||
    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
 | 
					    this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
 | 
				
			||||||
                              get_reg_ptr(traits::LAST_BRANCH), false);
 | 
					                              get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
 | 
				
			||||||
    std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
 | 
					    std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
 | 
				
			||||||
                              this->adj_to64(this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), false))};
 | 
					                              this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
 | 
				
			||||||
    this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
 | 
					    this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
 | 
				
			||||||
    auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false);
 | 
					    auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
 | 
				
			||||||
    this->builder.CreateRet(trap_addr_val);
 | 
					    this->builder.CreateRet(trap_addr_val);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
 | 
					template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
 | 
				
			||||||
    auto* target_bb = BasicBlock::Create(this->mod->getContext(), "", this->func, bb);
 | 
					    auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
 | 
				
			||||||
    auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
 | 
					 | 
				
			||||||
    this->gen_cond_branch(this->builder.CreateICmp(
 | 
					    this->gen_cond_branch(this->builder.CreateICmp(
 | 
				
			||||||
                              ICmpInst::ICMP_EQ, v,
 | 
					                              ICmpInst::ICMP_EQ, v,
 | 
				
			||||||
                              ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
 | 
					                              ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
 | 
				
			||||||
                          target_bb, this->trap_blk, 1);
 | 
					                          bb, this->trap_blk, 1);
 | 
				
			||||||
    this->builder.SetInsertPoint(target_bb);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ${coreDef.name.toLowerCase()}
 | 
					} // namespace ${coreDef.name.toLowerCase()}
 | 
				
			||||||
@@ -358,25 +323,3 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
} // namespace llvm
 | 
					} // namespace llvm
 | 
				
			||||||
} // namespace iss
 | 
					} // 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}};
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -120,7 +120,57 @@ 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(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(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>
 | 
					    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
				
			||||||
    inline S sext(U from) {
 | 
					    inline S sext(U from) {
 | 
				
			||||||
        auto mask = (1ULL<<W) - 1;
 | 
					        auto mask = (1ULL<<W) - 1;
 | 
				
			||||||
@@ -132,23 +182,14 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        compile_func op;
 | 
					        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){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
					         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
				
			||||||
        /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
 | 
					        /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
 | 
				
			||||||
        {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
					        {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
				
			||||||
@@ -159,7 +200,6 @@ private:
 | 
				
			|||||||
    compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
 | 
					    compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
 | 
				
			||||||
        tu("${instr.name}_{:#010x}:", pc.val);
 | 
					        tu("${instr.name}_{:#010x}:", pc.val);
 | 
				
			||||||
        vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
 | 
					        vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
 | 
				
			||||||
        uint64_t PC = pc.val;
 | 
					 | 
				
			||||||
        <%instr.fields.eachLine{%>${it}
 | 
					        <%instr.fields.eachLine{%>${it}
 | 
				
			||||||
        <%}%>if(this->disass_enabled){
 | 
					        <%}%>if(this->disass_enabled){
 | 
				
			||||||
            /* generate console output when executing the command */<%instr.disass.eachLine{%>
 | 
					            /* generate console output when executing the command */<%instr.disass.eachLine{%>
 | 
				
			||||||
@@ -168,12 +208,11 @@ private:
 | 
				
			|||||||
        auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
 | 
					        auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
 | 
				
			||||||
        pc=pc+ ${instr.length/8};
 | 
					        pc=pc+ ${instr.length/8};
 | 
				
			||||||
        gen_set_pc(tu, pc, traits::NEXT_PC);
 | 
					        gen_set_pc(tu, pc, traits::NEXT_PC);
 | 
				
			||||||
        tu.open_scope();
 | 
					        tu.open_scope();<%instr.behavior.eachLine{%>
 | 
				
			||||||
        <%instr.behavior.eachLine{%>${it}
 | 
					        ${it}<%}%>
 | 
				
			||||||
        <%}%>
 | 
					 | 
				
			||||||
        tu.close_scope();
 | 
					        tu.close_scope();
 | 
				
			||||||
        gen_trap_check(tu);        
 | 
					 | 
				
			||||||
        vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
 | 
					        vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
 | 
				
			||||||
 | 
					        gen_trap_check(tu);
 | 
				
			||||||
        return returnValue;
 | 
					        return returnValue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    <%}%>
 | 
					    <%}%>
 | 
				
			||||||
@@ -188,64 +227,11 @@ private:
 | 
				
			|||||||
        vm_impl::gen_trap_check(tu);
 | 
					        vm_impl::gen_trap_check(tu);
 | 
				
			||||||
        return BRANCH;
 | 
					        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 instr) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
    volatile CODE_WORD x = instr;
 | 
					    volatile CODE_WORD x = insn;
 | 
				
			||||||
    instr = 2 * x;
 | 
					    insn = 2 * x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
					template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			||||||
@@ -253,11 +239,14 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    qlut[0] = lut_00.data();
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    qlut[1] = lut_01.data();
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
@@ -265,11 +254,11 @@ std::tuple<continuation_e>
 | 
				
			|||||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
 | 
					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
 | 
					    // we fetch at max 4 byte, alignment is 2
 | 
				
			||||||
    enum {TRAP_ID=1<<16};
 | 
					    enum {TRAP_ID=1<<16};
 | 
				
			||||||
    code_word_t instr = 0;
 | 
					    code_word_t insn = 0;
 | 
				
			||||||
 | 
					    // const typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
				
			||||||
    phys_addr_t paddr(pc);
 | 
					    phys_addr_t paddr(pc);
 | 
				
			||||||
    if(this->core.has_mmu())
 | 
					    auto *const data = (uint8_t *)&insn;
 | 
				
			||||||
        paddr = this->core.virt2phys(pc);
 | 
					    paddr = this->core.v2p(pc);
 | 
				
			||||||
    //TODO: re-add page handling
 | 
					 | 
				
			||||||
//    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
					//    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
//        auto res = this->core.read(paddr, 2, data);
 | 
					//        auto res = this->core.read(paddr, 2, data);
 | 
				
			||||||
//        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					//        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
				
			||||||
@@ -277,17 +266,18 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
 | 
				
			|||||||
//            res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
 | 
					//            res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
 | 
				
			||||||
//        }
 | 
					//        }
 | 
				
			||||||
//    } else {
 | 
					//    } else {
 | 
				
			||||||
        auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
 | 
					        auto res = this->core.read(paddr, 4, data);
 | 
				
			||||||
        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
				
			||||||
//    }
 | 
					//    }
 | 
				
			||||||
    if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					    if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
				
			||||||
    // curr pc on stack
 | 
					    // curr pc on stack
 | 
				
			||||||
    ++inst_cnt;
 | 
					    ++inst_cnt;
 | 
				
			||||||
    auto f = decode_instr(root, instr);
 | 
					    auto lut_val = extract_fields(insn);
 | 
				
			||||||
 | 
					    auto f = qlut[insn & 0x3][lut_val];
 | 
				
			||||||
    if (f == nullptr) {
 | 
					    if (f == nullptr) {
 | 
				
			||||||
        f = &this_class::illegal_intruction;
 | 
					        f = &this_class::illegal_intruction;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (this->*f)(pc, instr, tu);
 | 
					    return (this->*f)(pc, insn, tu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
				
			||||||
@@ -306,13 +296,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) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
 | 
				
			||||||
    tu("trap_entry:");
 | 
					    tu("trap_entry:");
 | 
				
			||||||
    this->gen_sync(tu, POST_SYNC, -1);    
 | 
					 | 
				
			||||||
    tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
 | 
					    tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
 | 
				
			||||||
    tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
 | 
					    tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
 | 
				
			||||||
    tu("return *next_pc;");
 | 
					    tu("return *next_pc;");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ${coreDef.name.toLowerCase()}
 | 
					} // namespace mnrv32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -328,7 +317,7 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					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>{
 | 
					        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* 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);
 | 
							    auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
@@ -344,3 +333,8 @@ volatile std::array<bool, 2> dummy = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_${coreDef.name.toLowerCase()}_tcc_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src-gen/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src-gen/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,2 @@
 | 
				
			|||||||
/iss
 | 
					/iss
 | 
				
			||||||
/vm
 | 
					/vm
 | 
				
			||||||
/sysc
 | 
					 | 
				
			||||||
@@ -304,9 +304,9 @@ protected:
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
					        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_pc() override { return arch.reg.PC; }
 | 
					        uint64_t get_pc() override { return arch.reg.PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
 | 
					        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
					        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -316,11 +316,9 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
					        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void update_last_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; }
 | 
					        bool is_branch_taken() override { return arch.reg.last_branch; };
 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsigned get_reg_num() override {return traits<BASE>::NUM_REGS;}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        riscv_hart_m_p<BASE, FEAT> &arch;
 | 
					        riscv_hart_m_p<BASE, FEAT> &arch;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -668,7 +666,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
 | 
				
			|||||||
                    fault_data=addr;
 | 
					                    fault_data=addr;
 | 
				
			||||||
                    return iss::Err;
 | 
					                    return iss::Err;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                phys_addr_t phys_addr{access, space, addr};
 | 
					                auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
                auto res = iss::Err;
 | 
					                auto res = iss::Err;
 | 
				
			||||||
                if(access != access_type::FETCH && 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){
 | 
					                    auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
 | 
				
			||||||
@@ -761,7 +759,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
 | 
				
			|||||||
                    fault_data=addr;
 | 
					                    fault_data=addr;
 | 
				
			||||||
                    return iss::Err;
 | 
					                    return iss::Err;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                phys_addr_t phys_addr{access, space, addr};
 | 
					                auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
                auto res = iss::Err;
 | 
					                auto res = iss::Err;
 | 
				
			||||||
                if(access != access_type::FETCH && 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){
 | 
					                    auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
 | 
				
			||||||
@@ -786,8 +784,9 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
 | 
				
			|||||||
                return iss::Err;
 | 
					                return iss::Err;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ((addr + length) > mem.size()) return iss::Err;
 | 
					            phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
            switch (addr) {
 | 
					            if ((paddr.val + length) > mem.size()) return iss::Err;
 | 
				
			||||||
 | 
					            switch (paddr.val) {
 | 
				
			||||||
            case 0x10013000: // UART0 base, TXFIFO reg
 | 
					            case 0x10013000: // UART0 base, TXFIFO reg
 | 
				
			||||||
            case 0x10023000: // UART1 base, TXFIFO reg
 | 
					            case 0x10023000: // UART1 base, TXFIFO reg
 | 
				
			||||||
                uart_buf << (char)data[0];
 | 
					                uart_buf << (char)data[0];
 | 
				
			||||||
@@ -799,16 +798,16 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return iss::Ok;
 | 
					                return iss::Ok;
 | 
				
			||||||
            case 0x10008000: { // HFROSC base, hfrosccfg reg
 | 
					            case 0x10008000: { // HFROSC base, hfrosccfg reg
 | 
				
			||||||
                auto &p = mem(addr / mem.page_size);
 | 
					                auto &p = mem(paddr.val / mem.page_size);
 | 
				
			||||||
                auto offs = addr & mem.page_addr_mask;
 | 
					                auto offs = paddr.val & mem.page_addr_mask;
 | 
				
			||||||
                std::copy(data, data + length, p.data() + offs);
 | 
					                std::copy(data, data + length, p.data() + offs);
 | 
				
			||||||
                auto &x = *(p.data() + offs + 3);
 | 
					                auto &x = *(p.data() + offs + 3);
 | 
				
			||||||
                if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
 | 
					                if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
 | 
				
			||||||
                return iss::Ok;
 | 
					                return iss::Ok;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            case 0x10008008: { // HFROSC base, pllcfg reg
 | 
					            case 0x10008008: { // HFROSC base, pllcfg reg
 | 
				
			||||||
                auto &p = mem(addr / mem.page_size);
 | 
					                auto &p = mem(paddr.val / mem.page_size);
 | 
				
			||||||
                auto offs = addr & mem.page_addr_mask;
 | 
					                auto offs = paddr.val & mem.page_addr_mask;
 | 
				
			||||||
                std::copy(data, data + length, p.data() + offs);
 | 
					                std::copy(data, data + length, p.data() + offs);
 | 
				
			||||||
                auto &x = *(p.data() + offs + 3);
 | 
					                auto &x = *(p.data() + offs + 3);
 | 
				
			||||||
                x |= 0x80; // set pll lock upon writing
 | 
					                x |= 0x80; // set pll lock upon writing
 | 
				
			||||||
@@ -1115,10 +1114,8 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        this->reg.trap_state=std::numeric_limits<uint32_t>::max();
 | 
					                        this->reg.trap_state=std::numeric_limits<uint32_t>::max();
 | 
				
			||||||
                        this->interrupt_sim=hostvar;
 | 
					                        this->interrupt_sim=hostvar;
 | 
				
			||||||
#ifndef WITH_TCC
 | 
					 | 
				
			||||||
                        throw(iss::simulation_stopped(hostvar));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					                        //throw(iss::simulation_stopped(hostvar));
 | 
				
			||||||
                    case 0x0101: {
 | 
					                    case 0x0101: {
 | 
				
			||||||
                        char c = static_cast<char>(hostvar & 0xff);
 | 
					                        char c = static_cast<char>(hostvar & 0xff);
 | 
				
			||||||
                        if (c == '\n' || c == 0) {
 | 
					                        if (c == '\n' || c == 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -286,7 +286,7 @@ public:
 | 
				
			|||||||
        return m[mode];
 | 
					        return m[mode];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    riscv_hart_msu_vp(feature_config cfg = feature_config{});
 | 
					    riscv_hart_msu_vp();
 | 
				
			||||||
    virtual ~riscv_hart_msu_vp() = default;
 | 
					    virtual ~riscv_hart_msu_vp() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void reset(uint64_t address) override;
 | 
					    void reset(uint64_t address) override;
 | 
				
			||||||
@@ -331,9 +331,9 @@ protected:
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
					        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_pc() override { return arch.reg.PC; }
 | 
					        uint64_t get_pc() override { return arch.reg.PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
 | 
					        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
					        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -343,11 +343,9 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
					        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void update_last_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; }
 | 
					        bool is_branch_taken() override { return arch.reg.last_branch; };
 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        riscv_hart_msu_vp<BASE> &arch;
 | 
					        riscv_hart_msu_vp<BASE> &arch;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -432,7 +430,6 @@ template <typename BASE>
 | 
				
			|||||||
riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
 | 
					riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
 | 
				
			||||||
: state()
 | 
					: state()
 | 
				
			||||||
, instr_if(*this) {
 | 
					, instr_if(*this) {
 | 
				
			||||||
    this->_has_mmu = true;
 | 
					 | 
				
			||||||
    // reset values
 | 
					    // reset values
 | 
				
			||||||
    csr[misa] = traits<BASE>::MISA_VAL;
 | 
					    csr[misa] = traits<BASE>::MISA_VAL;
 | 
				
			||||||
    csr[mvendorid] = 0x669;
 | 
					    csr[mvendorid] = 0x669;
 | 
				
			||||||
@@ -635,7 +632,9 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
 | 
				
			|||||||
                        return res;
 | 
					                        return res;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                auto res = read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
 | 
					                auto res = type==iss::address_type::PHYSICAL?
 | 
				
			||||||
 | 
					                        read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
 | 
				
			||||||
 | 
					                        read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
 | 
				
			||||||
                if (unlikely(res != iss::Ok)){
 | 
					                if (unlikely(res != iss::Ok)){
 | 
				
			||||||
                	this->reg.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;
 | 
					                    fault_data=addr;
 | 
				
			||||||
@@ -720,7 +719,6 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
 | 
				
			|||||||
                this->reg.trap_state = (1 << 31); // issue trap 0
 | 
					                this->reg.trap_state = (1 << 31); // issue trap 0
 | 
				
			||||||
                return iss::Err;
 | 
					                return iss::Err;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
					 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
 | 
					                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);
 | 
					                    vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
 | 
				
			||||||
@@ -733,7 +731,9 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
 | 
				
			|||||||
                        return res;
 | 
					                        return res;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                auto res = write_mem(paddr, length, data);
 | 
					                auto res = type==iss::address_type::PHYSICAL?
 | 
				
			||||||
 | 
					                        write_mem(phys_addr_t{access, space, addr}, length, data):
 | 
				
			||||||
 | 
					                        write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
 | 
				
			||||||
                if (unlikely(res != iss::Ok)) {
 | 
					                if (unlikely(res != iss::Ok)) {
 | 
				
			||||||
                    this->reg.trap_state = (1UL << 31) | (7UL << 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;
 | 
					                    fault_data=addr;
 | 
				
			||||||
@@ -745,6 +745,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
 | 
				
			|||||||
                return iss::Err;
 | 
					                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;
 | 
					            if ((paddr.val + length) > mem.size()) return iss::Err;
 | 
				
			||||||
            switch (paddr.val) {
 | 
					            switch (paddr.val) {
 | 
				
			||||||
            case 0x10013000: // UART0 base, TXFIFO reg
 | 
					            case 0x10013000: // UART0 base, TXFIFO reg
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -329,9 +329,9 @@ protected:
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
					        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_pc() override { return arch.reg.PC; }
 | 
					        uint64_t get_pc() override { return arch.reg.PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
 | 
					        uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
					        uint64_t get_instr_word() override { return arch.reg.instruction; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -341,11 +341,9 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
					        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void update_last_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; }
 | 
					        bool is_branch_taken() override { return arch.reg.last_branch; };
 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        riscv_hart_mu_p<BASE, FEAT> &arch;
 | 
					        riscv_hart_mu_p<BASE, FEAT> &arch;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -836,7 +834,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
 | 
				
			|||||||
                    fault_data=addr;
 | 
					                    fault_data=addr;
 | 
				
			||||||
                    return iss::Err;
 | 
					                    return iss::Err;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                phys_addr_t phys_addr{access, space, addr};
 | 
					                auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
                auto res = iss::Err;
 | 
					                auto res = iss::Err;
 | 
				
			||||||
                if(!is_fetch(access) && 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){
 | 
					                    auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
 | 
				
			||||||
@@ -937,7 +935,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
 | 
				
			|||||||
                    fault_data=addr;
 | 
					                    fault_data=addr;
 | 
				
			||||||
                    return iss::Err;
 | 
					                    return iss::Err;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                phys_addr_t phys_addr{access, space, addr};
 | 
					                auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
                auto res = iss::Err;
 | 
					                auto res = iss::Err;
 | 
				
			||||||
                if(!is_fetch(access) && 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){
 | 
					                    auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
 | 
				
			||||||
@@ -962,29 +960,30 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
 | 
				
			|||||||
                return iss::Err;
 | 
					                return iss::Err;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ((addr + length) > mem.size()) return iss::Err;
 | 
					            phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
 | 
				
			||||||
            switch (addr) {
 | 
					            if ((paddr.val + length) > mem.size()) return iss::Err;
 | 
				
			||||||
 | 
					            switch (paddr.val) {
 | 
				
			||||||
            case 0x10013000: // UART0 base, TXFIFO reg
 | 
					            case 0x10013000: // UART0 base, TXFIFO reg
 | 
				
			||||||
            case 0x10023000: // UART1 base, TXFIFO reg
 | 
					            case 0x10023000: // UART1 base, TXFIFO reg
 | 
				
			||||||
                uart_buf << (char)data[0];
 | 
					                uart_buf << (char)data[0];
 | 
				
			||||||
                if (((char)data[0]) == '\n' || data[0] == 0) {
 | 
					                if (((char)data[0]) == '\n' || data[0] == 0) {
 | 
				
			||||||
                    // LOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send
 | 
					                    // LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
 | 
				
			||||||
                    // '"<<uart_buf.str()<<"'";
 | 
					                    // '"<<uart_buf.str()<<"'";
 | 
				
			||||||
                    std::cout << uart_buf.str();
 | 
					                    std::cout << uart_buf.str();
 | 
				
			||||||
                    uart_buf.str("");
 | 
					                    uart_buf.str("");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return iss::Ok;
 | 
					                return iss::Ok;
 | 
				
			||||||
            case 0x10008000: { // HFROSC base, hfrosccfg reg
 | 
					            case 0x10008000: { // HFROSC base, hfrosccfg reg
 | 
				
			||||||
                auto &p = mem(addr / mem.page_size);
 | 
					                auto &p = mem(paddr.val / mem.page_size);
 | 
				
			||||||
                auto offs = addr & mem.page_addr_mask;
 | 
					                auto offs = paddr.val & mem.page_addr_mask;
 | 
				
			||||||
                std::copy(data, data + length, p.data() + offs);
 | 
					                std::copy(data, data + length, p.data() + offs);
 | 
				
			||||||
                auto &x = *(p.data() + offs + 3);
 | 
					                auto &x = *(p.data() + offs + 3);
 | 
				
			||||||
                if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
 | 
					                if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
 | 
				
			||||||
                return iss::Ok;
 | 
					                return iss::Ok;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            case 0x10008008: { // HFROSC base, pllcfg reg
 | 
					            case 0x10008008: { // HFROSC base, pllcfg reg
 | 
				
			||||||
                auto &p = mem(addr / mem.page_size);
 | 
					                auto &p = mem(paddr.val / mem.page_size);
 | 
				
			||||||
                auto offs = addr & mem.page_addr_mask;
 | 
					                auto offs = paddr.val & mem.page_addr_mask;
 | 
				
			||||||
                std::copy(data, data + length, p.data() + offs);
 | 
					                std::copy(data, data + length, p.data() + offs);
 | 
				
			||||||
                auto &x = *(p.data() + offs + 3);
 | 
					                auto &x = *(p.data() + offs + 3);
 | 
				
			||||||
                x |= 0x80; // set pll lock upon writing
 | 
					                x |= 0x80; // set pll lock upon writing
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *******************************************************************************/
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "tgc5c.h"
 | 
					#include "tgc_c.h"
 | 
				
			||||||
#include "util/ities.h"
 | 
					#include "util/ities.h"
 | 
				
			||||||
#include <util/logging.h>
 | 
					#include <util/logging.h>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
@@ -39,18 +39,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace iss::arch;
 | 
					using namespace iss::arch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr std::array<const char*, 36>    iss::arch::traits<iss::arch::tgc5c>::reg_names;
 | 
					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::tgc5c>::reg_aliases;
 | 
					constexpr std::array<const char*, 36>    iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
 | 
				
			||||||
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc5c>::reg_bit_widths;
 | 
					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::tgc5c>::reg_byte_offsets;
 | 
					constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tgc5c::tgc5c()  = default;
 | 
					tgc_c::tgc_c()  = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tgc5c::~tgc5c() = default;
 | 
					tgc_c::~tgc_c() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tgc5c::reset(uint64_t address) {
 | 
					void tgc_c::reset(uint64_t address) {
 | 
				
			||||||
    auto base_ptr = reinterpret_cast<traits<tgc5c>::reg_t*>(get_regs_base_ptr());
 | 
					    auto base_ptr = reinterpret_cast<traits<tgc_c>::reg_t*>(get_regs_base_ptr());
 | 
				
			||||||
    for(size_t i=0; i<traits<tgc5c>::NUM_REGS; ++i)
 | 
					    for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i)
 | 
				
			||||||
        *(base_ptr+i)=0;
 | 
					        *(base_ptr+i)=0;
 | 
				
			||||||
    reg.PC=address;
 | 
					    reg.PC=address;
 | 
				
			||||||
    reg.NEXT_PC=reg.PC;
 | 
					    reg.NEXT_PC=reg.PC;
 | 
				
			||||||
@@ -59,11 +59,11 @@ void tgc5c::reset(uint64_t address) {
 | 
				
			|||||||
    reg.icount=0;
 | 
					    reg.icount=0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t *tgc5c::get_regs_base_ptr() {
 | 
					uint8_t *tgc_c::get_regs_base_ptr() {
 | 
				
			||||||
	return reinterpret_cast<uint8_t*>(®);
 | 
						return reinterpret_cast<uint8_t*>(®);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &addr) {
 | 
					tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
 | 
				
			||||||
    return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc5c>::addr_mask);
 | 
					    return phys_addr_t(pc); // change logical address to physical address
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,8 +30,8 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *******************************************************************************/
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _TGC5C_H_
 | 
					#ifndef _TGC_C_H_
 | 
				
			||||||
#define _TGC5C_H_
 | 
					#define _TGC_C_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <iss/arch/traits.h>
 | 
					#include <iss/arch/traits.h>
 | 
				
			||||||
@@ -41,19 +41,19 @@
 | 
				
			|||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace arch {
 | 
					namespace arch {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tgc5c;
 | 
					struct tgc_c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <> struct traits<tgc5c> {
 | 
					template <> struct traits<tgc_c> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static char const* const core_type = "TGC5C";
 | 
					    constexpr static char const* const core_type = "TGC_C";
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    static constexpr std::array<const char*, 36> reg_names{
 | 
					    static constexpr std::array<const char*, 36> reg_names{
 | 
				
			||||||
        {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc", "next_pc", "priv", "dpc"}};
 | 
					        {"X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15", "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", "X24", "X25", "X26", "X27", "X28", "X29", "X30", "X31", "PC", "NEXT_PC", "PRIV", "DPC"}};
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    static constexpr std::array<const char*, 36> reg_aliases{
 | 
					    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"}};
 | 
					        {"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL};
 | 
					    enum constants {MISA_VAL=1073746180, MARCHID_VAL=2147483651, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static unsigned FP_REGS_SIZE = 0;
 | 
					    constexpr static unsigned FP_REGS_SIZE = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,49 +141,49 @@ template <> struct traits<tgc5c> {
 | 
				
			|||||||
        DIVU = 54,
 | 
					        DIVU = 54,
 | 
				
			||||||
        REM = 55,
 | 
					        REM = 55,
 | 
				
			||||||
        REMU = 56,
 | 
					        REMU = 56,
 | 
				
			||||||
        C__ADDI4SPN = 57,
 | 
					        CADDI4SPN = 57,
 | 
				
			||||||
        C__LW = 58,
 | 
					        CLW = 58,
 | 
				
			||||||
        C__SW = 59,
 | 
					        CSW = 59,
 | 
				
			||||||
        C__ADDI = 60,
 | 
					        CADDI = 60,
 | 
				
			||||||
        C__NOP = 61,
 | 
					        CNOP = 61,
 | 
				
			||||||
        C__JAL = 62,
 | 
					        CJAL = 62,
 | 
				
			||||||
        C__LI = 63,
 | 
					        CLI = 63,
 | 
				
			||||||
        C__LUI = 64,
 | 
					        CLUI = 64,
 | 
				
			||||||
        C__ADDI16SP = 65,
 | 
					        CADDI16SP = 65,
 | 
				
			||||||
        __reserved_clui = 66,
 | 
					        __reserved_clui = 66,
 | 
				
			||||||
        C__SRLI = 67,
 | 
					        CSRLI = 67,
 | 
				
			||||||
        C__SRAI = 68,
 | 
					        CSRAI = 68,
 | 
				
			||||||
        C__ANDI = 69,
 | 
					        CANDI = 69,
 | 
				
			||||||
        C__SUB = 70,
 | 
					        CSUB = 70,
 | 
				
			||||||
        C__XOR = 71,
 | 
					        CXOR = 71,
 | 
				
			||||||
        C__OR = 72,
 | 
					        COR = 72,
 | 
				
			||||||
        C__AND = 73,
 | 
					        CAND = 73,
 | 
				
			||||||
        C__J = 74,
 | 
					        CJ = 74,
 | 
				
			||||||
        C__BEQZ = 75,
 | 
					        CBEQZ = 75,
 | 
				
			||||||
        C__BNEZ = 76,
 | 
					        CBNEZ = 76,
 | 
				
			||||||
        C__SLLI = 77,
 | 
					        CSLLI = 77,
 | 
				
			||||||
        C__LWSP = 78,
 | 
					        CLWSP = 78,
 | 
				
			||||||
        C__MV = 79,
 | 
					        CMV = 79,
 | 
				
			||||||
        C__JR = 80,
 | 
					        CJR = 80,
 | 
				
			||||||
        __reserved_cmv = 81,
 | 
					        __reserved_cmv = 81,
 | 
				
			||||||
        C__ADD = 82,
 | 
					        CADD = 82,
 | 
				
			||||||
        C__JALR = 83,
 | 
					        CJALR = 83,
 | 
				
			||||||
        C__EBREAK = 84,
 | 
					        CEBREAK = 84,
 | 
				
			||||||
        C__SWSP = 85,
 | 
					        CSWSP = 85,
 | 
				
			||||||
        DII = 86,
 | 
					        DII = 86,
 | 
				
			||||||
        MAX_OPCODE
 | 
					        MAX_OPCODE
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tgc5c: public arch_if {
 | 
					struct tgc_c: public arch_if {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using virt_addr_t = typename traits<tgc5c>::virt_addr_t;
 | 
					    using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
 | 
				
			||||||
    using phys_addr_t = typename traits<tgc5c>::phys_addr_t;
 | 
					    using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
 | 
				
			||||||
    using reg_t =  typename traits<tgc5c>::reg_t;
 | 
					    using reg_t =  typename traits<tgc_c>::reg_t;
 | 
				
			||||||
    using addr_t = typename traits<tgc5c>::addr_t;
 | 
					    using addr_t = typename traits<tgc_c>::addr_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tgc5c();
 | 
					    tgc_c();
 | 
				
			||||||
    ~tgc5c();
 | 
					    ~tgc_c();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void reset(uint64_t address=0) override;
 | 
					    void reset(uint64_t address=0) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -195,6 +195,14 @@ struct tgc5c: public arch_if {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    inline uint64_t stop_code() { 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 phys_addr_t virt2phys(const iss::addr_t& addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
 | 
					    virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
 | 
				
			||||||
@@ -203,7 +211,7 @@ struct tgc5c: public arch_if {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma pack(push, 1)
 | 
					#pragma pack(push, 1)
 | 
				
			||||||
    struct TGC5C_regs { 
 | 
					    struct TGC_C_regs { 
 | 
				
			||||||
        uint32_t X0 = 0; 
 | 
					        uint32_t X0 = 0; 
 | 
				
			||||||
        uint32_t X1 = 0; 
 | 
					        uint32_t X1 = 0; 
 | 
				
			||||||
        uint32_t X2 = 0; 
 | 
					        uint32_t X2 = 0; 
 | 
				
			||||||
@@ -259,4 +267,4 @@ struct tgc5c: public arch_if {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}            
 | 
					}            
 | 
				
			||||||
#endif /* _TGC5C_H_ */
 | 
					#endif /* _TGC_C_H_ */
 | 
				
			||||||
							
								
								
									
										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>>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,49 +2,49 @@
 | 
				
			|||||||
#define _ISS_ARCH_TGC_MAPPER_H
 | 
					#define _ISS_ARCH_TGC_MAPPER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "riscv_hart_m_p.h"
 | 
					#include "riscv_hart_m_p.h"
 | 
				
			||||||
#include "tgc5c.h"
 | 
					#include "tgc_c.h"
 | 
				
			||||||
using tgc5c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5c>;
 | 
					using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
 | 
				
			||||||
#ifdef CORE_TGC5A
 | 
					#ifdef CORE_TGC_A
 | 
				
			||||||
#include "riscv_hart_m_p.h"
 | 
					#include "riscv_hart_m_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5a.h>
 | 
					#include <iss/arch/tgc_a.h>
 | 
				
			||||||
using tgc5a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5a>;
 | 
					using tgc_a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_a>;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5B
 | 
					#ifdef CORE_TGC_B
 | 
				
			||||||
#include "riscv_hart_m_p.h"
 | 
					#include "riscv_hart_m_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5b.h>
 | 
					#include <iss/arch/tgc_b.h>
 | 
				
			||||||
using tgc5b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc5b>;
 | 
					using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5C_XRB_NN
 | 
					#ifdef CORE_TGC_C_XRB_NN
 | 
				
			||||||
#include "riscv_hart_m_p.h"
 | 
					#include "riscv_hart_m_p.h"
 | 
				
			||||||
#include "hwl.h"
 | 
					#include "hwl.h"
 | 
				
			||||||
#include <iss/arch/tgc5c_xrb_nn.h>
 | 
					#include <iss/arch/tgc_c_xrb_nn.h>
 | 
				
			||||||
using tgc5c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc5c_xrb_nn>>;
 | 
					using tgc_c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>>;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5D
 | 
					#ifdef CORE_TGC_D
 | 
				
			||||||
#include "riscv_hart_mu_p.h"
 | 
					#include "riscv_hart_mu_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5d.h>
 | 
					#include <iss/arch/tgc_d.h>
 | 
				
			||||||
using tgc5d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
					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
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5D_XRB_MAC
 | 
					#ifdef CORE_TGC_D_XRB_MAC
 | 
				
			||||||
#include "riscv_hart_mu_p.h"
 | 
					#include "riscv_hart_mu_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5d_xrb_mac.h>
 | 
					#include <iss/arch/tgc_d_xrb_mac.h>
 | 
				
			||||||
using tgc5d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
					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
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5D_XRB_NN
 | 
					#ifdef CORE_TGC_D_XRB_NN
 | 
				
			||||||
#include "riscv_hart_mu_p.h"
 | 
					#include "riscv_hart_mu_p.h"
 | 
				
			||||||
#include "hwl.h"
 | 
					#include "hwl.h"
 | 
				
			||||||
#include <iss/arch/tgc5d_xrb_nn.h>
 | 
					#include <iss/arch/tgc_d_xrb_nn.h>
 | 
				
			||||||
using tgc5d_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_mu_p<iss::arch::tgc5d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>>;
 | 
					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
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5E
 | 
					#ifdef CORE_TGC_E
 | 
				
			||||||
#include "riscv_hart_mu_p.h"
 | 
					#include "riscv_hart_mu_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5e.h>
 | 
					#include <iss/arch/tgc_e.h>
 | 
				
			||||||
using tgc5e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
					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
 | 
					#endif
 | 
				
			||||||
#ifdef CORE_TGC5X
 | 
					#ifdef CORE_TGC_X
 | 
				
			||||||
#include "riscv_hart_mu_p.h"
 | 
					#include "riscv_hart_mu_p.h"
 | 
				
			||||||
#include <iss/arch/tgc5x.h>
 | 
					#include <iss/arch/tgc_x.h>
 | 
				
			||||||
using tgc5x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc5x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
 | 
					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
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,17 +80,9 @@ class core_factory {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
    static core_factory & instance() { static core_factory bf; return bf; }
 | 
					    static core_factory & instance() { static core_factory bf; return bf; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool register_creator(const std::string & className, create_fn const& fn) {
 | 
					    bool register_creator(const std::string &, create_fn const&);
 | 
				
			||||||
        registry[className] = fn;
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
 | 
					    base_t create(const std::string &, 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> get_names() {
 | 
				
			||||||
        std::vector<std::string> keys{registry.size()};
 | 
					        std::vector<std::string> keys{registry.size()};
 | 
				
			||||||
@@ -101,6 +93,18 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool core_factory::register_creator(const std::string & className, create_fn const& fn) {
 | 
				
			||||||
 | 
					    registry[className] = fn;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline core_factory::base_t core_factory::create(const std::string &className, unsigned gdb_port, void* data) const {
 | 
				
			||||||
 | 
					    registry_t::const_iterator regEntry = registry.find(className);
 | 
				
			||||||
 | 
					    if (regEntry != registry.end())
 | 
				
			||||||
 | 
					        return regEntry->second(gdb_port, data);
 | 
				
			||||||
 | 
					    return {nullptr, nullptr};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ISS_FACTORY_H_ */
 | 
					#endif /* _ISS_FACTORY_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
# pctrace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Trace functionality to allow visualizing coverage in lcov and cachegrind tools. Use environment variables NOCOMPRES and REGDUMP to toggle functionality.
 | 
					 | 
				
			||||||
- NOCOMPRES: any value turns off the LZ4 compression
 | 
					 | 
				
			||||||
- REGDUMP: any value switches to tracing the registers instead. Also turns off compression.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Known Bugs: 
 | 
					 | 
				
			||||||
- currently does not work correctly with jit backends, the plugin cant tell if instructions are compressed. Additionaly the cost of instrs that raise a trap is not known. It takes the cost of the instrid -1 (0 at the moment).
 | 
					 | 
				
			||||||
							
								
								
									
										214
									
								
								src/iss/plugin/pctrace.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/iss/plugin/pctrace.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * 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/ostreamwrapper.h>
 | 
				
			||||||
 | 
					#include <rapidjson/error/en.h>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#ifdef WITH_LZ4
 | 
				
			||||||
 | 
					#include <lz4frame.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace iss {
 | 
				
			||||||
 | 
					namespace plugin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace rapidjson;
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef WITH_LZ4
 | 
				
			||||||
 | 
					class lz4compress_steambuf: public std::streambuf {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    lz4compress_steambuf(const lz4compress_steambuf&) = delete;
 | 
				
			||||||
 | 
					    lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
 | 
				
			||||||
 | 
					    lz4compress_steambuf(std::ostream &sink, size_t buf_size)
 | 
				
			||||||
 | 
					    : sink(sink)
 | 
				
			||||||
 | 
					    , src_buf(buf_size)
 | 
				
			||||||
 | 
					    , dest_buf(LZ4F_compressBound(buf_size, nullptr))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
 | 
				
			||||||
 | 
					        if (LZ4F_isError(errCode) != 0)
 | 
				
			||||||
 | 
					            throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
 | 
				
			||||||
 | 
					        size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr);
 | 
				
			||||||
 | 
					        if (LZ4F_isError(ret) != 0)
 | 
				
			||||||
 | 
					            throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret));
 | 
				
			||||||
 | 
					        setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
 | 
				
			||||||
 | 
					        sink.write(dest_buf.data(), ret);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~lz4compress_steambuf() {
 | 
				
			||||||
 | 
					        close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void close() {
 | 
				
			||||||
 | 
					        if (closed)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        sync();
 | 
				
			||||||
 | 
					        auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
 | 
				
			||||||
 | 
					        if (LZ4F_isError(ret) != 0)
 | 
				
			||||||
 | 
					            throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret));
 | 
				
			||||||
 | 
					        sink.write(dest_buf.data(), ret);
 | 
				
			||||||
 | 
					        LZ4F_freeCompressionContext(ctx);
 | 
				
			||||||
 | 
					        closed = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    int_type overflow(int_type ch) override {
 | 
				
			||||||
 | 
					        compress_and_write();
 | 
				
			||||||
 | 
					        *pptr() = static_cast<char_type>(ch);
 | 
				
			||||||
 | 
					        pbump(1);
 | 
				
			||||||
 | 
					        return ch;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int_type sync() override {
 | 
				
			||||||
 | 
					        compress_and_write();
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void compress_and_write() {
 | 
				
			||||||
 | 
					        if (closed)
 | 
				
			||||||
 | 
					            throw std::runtime_error("Cannot write to closed stream");
 | 
				
			||||||
 | 
					        if(auto orig_size = pptr() - pbase()){
 | 
				
			||||||
 | 
					            auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
 | 
				
			||||||
 | 
					            if (LZ4F_isError(ret) != 0)
 | 
				
			||||||
 | 
					                throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
 | 
				
			||||||
 | 
					            if(ret) sink.write(dest_buf.data(), ret);
 | 
				
			||||||
 | 
					            pbump(-orig_size);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::ostream &sink;
 | 
				
			||||||
 | 
					    std::vector<char> src_buf;
 | 
				
			||||||
 | 
					    std::vector<char> dest_buf;
 | 
				
			||||||
 | 
					    LZ4F_compressionContext_t ctx{ nullptr };
 | 
				
			||||||
 | 
					    bool closed{ false };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pctrace::pctrace(std::string const &filename)
 | 
				
			||||||
 | 
					: instr_if(nullptr)
 | 
				
			||||||
 | 
					, filename(filename)
 | 
				
			||||||
 | 
					, output("output.trc")
 | 
				
			||||||
 | 
					#ifdef WITH_LZ4
 | 
				
			||||||
 | 
					, strbuf(new lz4compress_steambuf(output, 4096))
 | 
				
			||||||
 | 
					, ostr(strbuf.get())
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					{ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pctrace::~pctrace() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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();
 | 
				
			||||||
 | 
					    if (filename.length() > 0) {
 | 
				
			||||||
 | 
					        ifstream is(filename);
 | 
				
			||||||
 | 
					        if (is.is_open()) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                IStreamWrapper isw(is);
 | 
				
			||||||
 | 
					                Document d;
 | 
				
			||||||
 | 
					                ParseResult ok = d.ParseStream(isw);
 | 
				
			||||||
 | 
					                if(ok) {
 | 
				
			||||||
 | 
					                    Value& val = d[core_name.c_str()];
 | 
				
			||||||
 | 
					                    if(val.IsArray()){
 | 
				
			||||||
 | 
					                        delays.reserve(val.Size());
 | 
				
			||||||
 | 
					                        for (auto it = val.Begin(); it != val.End(); ++it) {
 | 
				
			||||||
 | 
					                            auto& name = (*it)["name"];
 | 
				
			||||||
 | 
					                            auto& size = (*it)["size"];
 | 
				
			||||||
 | 
					                            auto& delay = (*it)["delay"];
 | 
				
			||||||
 | 
					                            auto& branch = (*it)["branch"];
 | 
				
			||||||
 | 
					                            if(delay.IsArray()) {
 | 
				
			||||||
 | 
					                                auto dt = delay[0].Get<unsigned>();
 | 
				
			||||||
 | 
					                                auto dnt = delay[1].Get<unsigned>();
 | 
				
			||||||
 | 
					                                delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
 | 
				
			||||||
 | 
					                            } else if(delay.Is<unsigned>()) {
 | 
				
			||||||
 | 
					                                auto d = delay.Get<unsigned>();
 | 
				
			||||||
 | 
					                                delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
 | 
				
			||||||
 | 
					                            } else
 | 
				
			||||||
 | 
					                                throw runtime_error("JSON parse error");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (runtime_error &e) {
 | 
				
			||||||
 | 
					                LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            LOG(ERR) << "Could not open input file " << filename;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 = instr_if->is_branch_taken();
 | 
				
			||||||
 | 
					    bool compressed = (instr&0x3)!=0x3;
 | 
				
			||||||
 | 
					    if (taken) {
 | 
				
			||||||
 | 
					        delay = entry.taken;
 | 
				
			||||||
 | 
					        if(entry.taken > 1)
 | 
				
			||||||
 | 
					            instr_if->update_last_instr_cycles(entry.taken);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        delay = entry.not_taken;
 | 
				
			||||||
 | 
					        if (entry.not_taken > 1)
 | 
				
			||||||
 | 
					            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";
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    auto rdbuf=ostr.rdbuf();
 | 
				
			||||||
 | 
					    ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					/*******************************************************************************
 | 
				
			||||||
 * Copyright (C) 2021 MINRES Technologies GmbH
 | 
					 * Copyright (C) 2017 - 2023, MINRES Technologies GmbH
 | 
				
			||||||
 * All rights reserved.
 | 
					 * All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Redistribution and use in source and binary forms, with or without
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
@@ -28,61 +28,75 @@
 | 
				
			|||||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
					 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
				
			||||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
					 * POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *******************************************************************************/
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *       eyck@minres.com - initial API and implementation
 | 
				
			||||||
 | 
					 ******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _ISS_FACTORY_H_
 | 
					#ifndef _ISS_PLUGIN_COV_H_
 | 
				
			||||||
#define _ISS_FACTORY_H_
 | 
					#define _ISS_PLUGIN_COV_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/vm_plugin.h>
 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					#include "iss/instrumentation_if.h"
 | 
				
			||||||
#include <memory>
 | 
					#include <json/json.h>
 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <fstream>
 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace sysc {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using sc_cpu_ptr = std::unique_ptr<sc_core_adapter_if>;
 | 
					namespace iss {
 | 
				
			||||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
 | 
					namespace plugin {
 | 
				
			||||||
 | 
					class lz4compress_steambuf;
 | 
				
			||||||
 | 
					class pctrace : public iss::vm_plugin {
 | 
				
			||||||
 | 
					    struct instr_delay {
 | 
				
			||||||
 | 
					        std::string instr_name;
 | 
				
			||||||
 | 
					        size_t size;
 | 
				
			||||||
 | 
					        size_t not_taken_delay;
 | 
				
			||||||
 | 
					        size_t taken_delay;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    BEGIN_BF_DECL(instr_desc, uint32_t)
 | 
				
			||||||
 | 
					        BF_FIELD(taken, 24, 8)
 | 
				
			||||||
 | 
					        BF_FIELD(not_taken, 16, 8)
 | 
				
			||||||
 | 
					        BF_FIELD(is_branch, 8, 8)
 | 
				
			||||||
 | 
					        BF_FIELD(size, 0, 8)
 | 
				
			||||||
 | 
					        instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
 | 
				
			||||||
 | 
					            this->size=size;
 | 
				
			||||||
 | 
					            this->taken=taken;
 | 
				
			||||||
 | 
					            this->not_taken=not_taken;
 | 
				
			||||||
 | 
					            this->is_branch=branch;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    END_BF_DECL();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class iss_factory {
 | 
					 | 
				
			||||||
public:
 | 
					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;
 | 
					    pctrace(const pctrace &) = delete;
 | 
				
			||||||
    iss_factory(const iss_factory &) = delete;
 | 
					 | 
				
			||||||
    iss_factory & operator=(const iss_factory &) = delete;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static iss_factory & instance() { static iss_factory bf; return bf; }
 | 
					    pctrace(const pctrace &&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool register_creator(const std::string & className, create_fn const& fn) {
 | 
					    pctrace(std::string const &);
 | 
				
			||||||
        registry[className] = fn;
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
 | 
					    virtual ~pctrace();
 | 
				
			||||||
        registry_t::const_iterator regEntry = registry.find(className);
 | 
					
 | 
				
			||||||
        if (regEntry != registry.end())
 | 
					    pctrace &operator=(const pctrace &) = delete;
 | 
				
			||||||
            return regEntry->second(gdb_port, init_data);
 | 
					
 | 
				
			||||||
        return {nullptr, nullptr};
 | 
					    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) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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:
 | 
					private:
 | 
				
			||||||
    registry_t registry;
 | 
					    iss::instrumentation_if *instr_if  {nullptr};
 | 
				
			||||||
 | 
					    std::ofstream output;
 | 
				
			||||||
 | 
					#ifdef WITH_LZ4
 | 
				
			||||||
 | 
					    std::unique_ptr<lz4compress_steambuf> strbuf;
 | 
				
			||||||
 | 
					    std::ostream ostr;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    std::string filename;
 | 
				
			||||||
 | 
					    std::vector<instr_desc> delays;
 | 
				
			||||||
 | 
					    bool jumped{false}, first{true};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ISS_FACTORY_H_ */
 | 
					#endif /* _ISS_PLUGIN_COV_H_ */
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/main.cpp
									
									
									
									
									
								
							@@ -39,11 +39,12 @@
 | 
				
			|||||||
#include <boost/program_options.hpp>
 | 
					#include <boost/program_options.hpp>
 | 
				
			||||||
#include "iss/arch/tgc_mapper.h"
 | 
					#include "iss/arch/tgc_mapper.h"
 | 
				
			||||||
#ifdef WITH_LLVM
 | 
					#ifdef WITH_LLVM
 | 
				
			||||||
#include <iss/llvm/jit_init.h>
 | 
					#include <iss/llvm/jit_helper.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <iss/log_categories.h>
 | 
					#include <iss/log_categories.h>
 | 
				
			||||||
#include "iss/plugin/cycle_estimate.h"
 | 
					#include "iss/plugin/cycle_estimate.h"
 | 
				
			||||||
#include "iss/plugin/instruction_count.h"
 | 
					#include "iss/plugin/instruction_count.h"
 | 
				
			||||||
 | 
					#include "iss/plugin/pctrace.h"
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
#include <iss/plugin/loader.h>
 | 
					#include <iss/plugin/loader.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -73,7 +74,7 @@ int main(int argc, char *argv[]) {
 | 
				
			|||||||
        ("mem,m", po::value<std::string>(), "the memory input file")
 | 
					        ("mem,m", po::value<std::string>(), "the memory input file")
 | 
				
			||||||
        ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
 | 
					        ("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")
 | 
					        ("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc")
 | 
				
			||||||
        ("isa", po::value<std::string>()->default_value("tgc5c"), "isa to use for simulation");
 | 
					        ("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
 | 
				
			||||||
    // clang-format on
 | 
					    // clang-format on
 | 
				
			||||||
    auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
 | 
					    auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
@@ -156,7 +157,11 @@ int main(int argc, char *argv[]) {
 | 
				
			|||||||
                    auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
 | 
					                    auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
 | 
				
			||||||
                    vm->register_plugin(*ce_plugin);
 | 
					                    vm->register_plugin(*ce_plugin);
 | 
				
			||||||
                    plugin_list.push_back(ce_plugin);
 | 
					                    plugin_list.push_back(ce_plugin);
 | 
				
			||||||
                }else {
 | 
					                } else if (plugin_name == "pctrace") {
 | 
				
			||||||
 | 
					                    auto *plugin = new iss::plugin::pctrace(arg);
 | 
				
			||||||
 | 
					                    vm->register_plugin(*plugin);
 | 
				
			||||||
 | 
					                    plugin_list.push_back(plugin);
 | 
				
			||||||
 | 
					               } else {
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
                    std::vector<char const*> a{};
 | 
					                    std::vector<char const*> a{};
 | 
				
			||||||
                    if(arg.length())
 | 
					                    if(arg.length())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,11 +37,10 @@
 | 
				
			|||||||
#include <iss/debugger/target_adapter_if.h>
 | 
					#include <iss/debugger/target_adapter_if.h>
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/iss.h>
 | 
				
			||||||
#include <iss/vm_types.h>
 | 
					#include <iss/vm_types.h>
 | 
				
			||||||
#include "iss_factory.h"
 | 
					 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
#include <iss/plugin/loader.h>
 | 
					#include <iss/plugin/loader.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
#include <iss/arch/tgc_mapper.h>
 | 
					#include <iss/arch/tgc_mapper.h>
 | 
				
			||||||
#include <scc/report.h>
 | 
					#include <scc/report.h>
 | 
				
			||||||
#include <util/ities.h>
 | 
					#include <util/ities.h>
 | 
				
			||||||
@@ -50,6 +49,7 @@
 | 
				
			|||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <iss/plugin/cycle_estimate.h>
 | 
					#include <iss/plugin/cycle_estimate.h>
 | 
				
			||||||
#include <iss/plugin/instruction_count.h>
 | 
					#include <iss/plugin/instruction_count.h>
 | 
				
			||||||
 | 
					#include <iss/plugin/pctrace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// clang-format on
 | 
					// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,9 +85,136 @@ using namespace sc_core;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
iss::debugger::encoder_decoder encdec;
 | 
					iss::debugger::encoder_decoder encdec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
 | 
					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->instr_if.get_total_cycles());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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->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();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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, is_fetch(addr.access)) ? 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->reg.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 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[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->reg.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,
 | 
					int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func df,
 | 
				
			||||||
             debugger::target_adapter_if *tgt_adapter) {
 | 
					             debugger::target_adapter_if *tgt_adapter) {
 | 
				
			||||||
    if (argc > 1) {
 | 
					    if (argc > 1) {
 | 
				
			||||||
@@ -127,9 +254,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void reset(uint64_t addr){vm->reset(addr);}
 | 
					    void reset(uint64_t addr){vm->reset(addr);}
 | 
				
			||||||
    inline void start(){vm->start();}
 | 
					    inline void start(){vm->start();}
 | 
				
			||||||
    inline std::pair<uint64_t, bool> load_file(std::string const& name){
 | 
					    inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
 | 
				
			||||||
        iss::arch_if* cc = cpu->get_arch_if();
 | 
					 | 
				
			||||||
        return cc->load_file(name);};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::function<unsigned(void)> get_mode;
 | 
					    std::function<unsigned(void)> get_mode;
 | 
				
			||||||
    std::function<uint64_t(void)> get_state;
 | 
					    std::function<uint64_t(void)> get_state;
 | 
				
			||||||
@@ -137,35 +262,45 @@ public:
 | 
				
			|||||||
    std::function<void(bool)> set_interrupt_execution;
 | 
					    std::function<void(bool)> set_interrupt_execution;
 | 
				
			||||||
    std::function<void(short, bool)> local_irq;
 | 
					    std::function<void(short, bool)> local_irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
 | 
					    template<typename PLAT>
 | 
				
			||||||
        auto & f = sysc::iss_factory::instance();
 | 
					    std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
 | 
				
			||||||
        if(type.size()==0 || type == "?") {
 | 
					        auto* lcpu = new core_wrapper_t<PLAT>(owner);
 | 
				
			||||||
            std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
 | 
					        lcpu->set_mhartid(hart_id);
 | 
				
			||||||
            sc_core::sc_stop();
 | 
					        get_mode = [lcpu]() { return lcpu->get_mode(); };
 | 
				
			||||||
        } else if (type.find('|') != std::string::npos) {
 | 
					        get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
 | 
				
			||||||
            std::tie(cpu, vm) = f.create(type+"|"+backend);
 | 
					        get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
 | 
				
			||||||
        } else {
 | 
					        set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
 | 
				
			||||||
            auto base_isa = type.substr(0, 5);
 | 
					        local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
 | 
				
			||||||
            if(base_isa=="tgc5d" || base_isa=="tgc5e") {
 | 
					        if(backend == "interp")
 | 
				
			||||||
                std::tie(cpu, vm) = f.create(type + "|mu_p_clic_pmp|" + backend, gdb_port);
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
 | 
				
			||||||
            } else {
 | 
					#ifdef WITH_LLVM
 | 
				
			||||||
                std::tie(cpu, vm) = f.create(type + "|m_p|" + backend, gdb_port, owner);
 | 
					        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};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        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); };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 *srv = debugger::server<debugger::gdb_session>::get();
 | 
					        auto *srv = debugger::server<debugger::gdb_session>::get();
 | 
				
			||||||
        if (srv) tgt_adapter = srv->get_target();
 | 
					        if (srv) tgt_adapter = srv->get_target();
 | 
				
			||||||
        if (tgt_adapter)
 | 
					        if (tgt_adapter)
 | 
				
			||||||
@@ -178,7 +313,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    core_complex * const owner;
 | 
					    core_complex * const owner;
 | 
				
			||||||
    vm_ptr vm{nullptr};
 | 
					    vm_ptr vm{nullptr};
 | 
				
			||||||
    sc_cpu_ptr cpu{nullptr};
 | 
					    cpu_ptr cpu{nullptr};
 | 
				
			||||||
    iss::debugger::target_adapter_if *tgt_adapter{nullptr};
 | 
					    iss::debugger::target_adapter_if *tgt_adapter{nullptr};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -282,6 +417,10 @@ void core_complex::before_end_of_elaboration() {
 | 
				
			|||||||
                auto *plugin = new iss::plugin::cycle_estimate(filename);
 | 
					                auto *plugin = new iss::plugin::cycle_estimate(filename);
 | 
				
			||||||
                cpu->vm->register_plugin(*plugin);
 | 
					                cpu->vm->register_plugin(*plugin);
 | 
				
			||||||
                plugin_list.push_back(plugin);
 | 
					                plugin_list.push_back(plugin);
 | 
				
			||||||
 | 
					            } else if (plugin_name == "pctrace") {
 | 
				
			||||||
 | 
					                auto *plugin = new iss::plugin::pctrace(filename);
 | 
				
			||||||
 | 
					                cpu->vm->register_plugin(*plugin);
 | 
				
			||||||
 | 
					                plugin_list.push_back(plugin);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
                std::array<char const*, 1> a{{filename.c_str()}};
 | 
					                std::array<char const*, 1> a{{filename.c_str()}};
 | 
				
			||||||
@@ -495,5 +634,5 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
 | 
				
			|||||||
    gp.set_streaming_width(length);
 | 
					    gp.set_streaming_width(length);
 | 
				
			||||||
    return dbus->transport_dbg(gp) == length;
 | 
					    return dbus->transport_dbg(gp) == length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} /* namespace tgfs */
 | 
					} /* namespace SiFive */
 | 
				
			||||||
} /* namespace sysc */
 | 
					} /* namespace sysc */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,7 +96,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
 | 
					    cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cci::cci_param<std::string> core_type{"core_type", "tgc5c"};
 | 
					    cci::cci_param<std::string> core_type{"core_type", "tgc_c"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cci::cci_param<std::string> backend{"backend", "interp"};
 | 
					    cci::cci_param<std::string> backend{"backend", "interp"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,7 +121,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    scml_property<unsigned long long> reset_address{"reset_address", 0ULL};
 | 
					    scml_property<unsigned long long> reset_address{"reset_address", 0ULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scml_property<std::string> core_type{"core_type", "tgc5c"};
 | 
					    scml_property<std::string> core_type{"core_type", "tgc_c"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    scml_property<std::string> backend{"backend", "interp"};
 | 
					    scml_property<std::string> backend{"backend", "interp"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,7 +139,7 @@ public:
 | 
				
			|||||||
    , elf_file{"elf_file", ""}
 | 
					    , elf_file{"elf_file", ""}
 | 
				
			||||||
    , enable_disass{"enable_disass", false}
 | 
					    , enable_disass{"enable_disass", false}
 | 
				
			||||||
    , reset_address{"reset_address", 0ULL}
 | 
					    , reset_address{"reset_address", 0ULL}
 | 
				
			||||||
    , core_type{"core_type", "tgc5c"}
 | 
					    , core_type{"core_type", "tgc_c"}
 | 
				
			||||||
    , backend{"backend", "interp"}
 | 
					    , backend{"backend", "interp"}
 | 
				
			||||||
    , gdb_server_port{"gdb_server_port", 0}
 | 
					    , gdb_server_port{"gdb_server_port", 0}
 | 
				
			||||||
    , dump_ir{"dump_ir", false}
 | 
					    , dump_ir{"dump_ir", false}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,74 +1,33 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2023 MINRES Technologies GmbH
 | 
					 * register_tgc_c.cpp
 | 
				
			||||||
 * All rights reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Redistribution and use in source and binary forms, with or without
 | 
					 *  Created on: Jul 5, 2023
 | 
				
			||||||
 * modification, are permitted provided that the following conditions are met:
 | 
					 *      Author: eyck
 | 
				
			||||||
 *
 | 
					 */
 | 
				
			||||||
 * 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/tgc5c.h>
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iss/factory.h>
 | 
				
			||||||
 | 
					#include <iss/arch/tgc_c.h>
 | 
				
			||||||
#include <iss/arch/riscv_hart_m_p.h>
 | 
					#include <iss/arch/riscv_hart_m_p.h>
 | 
				
			||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
#include "sc_core_adapter.h"
 | 
					#include "sc_core_adapter.h"
 | 
				
			||||||
#include "core_complex.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
#include <array>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace interp {
 | 
					namespace {
 | 
				
			||||||
using namespace sysc;
 | 
					volatile std::array<bool, 2> dummy = {
 | 
				
			||||||
volatile std::array<bool, 2> tgc_init = {
 | 
					        core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
        iss_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
 | 
					            arch::tgc_c* lcpu = 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::tgc5c*>(cpu), gdb_port)}};
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        iss_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					        core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
 | 
					            arch::tgc_c* lcpu = 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::tgc5c*>(cpu), gdb_port)}};
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#if defined(WITH_TCC)
 | 
					 | 
				
			||||||
namespace tcc {
 | 
					 | 
				
			||||||
using namespace sysc;
 | 
					 | 
				
			||||||
volatile std::array<bool, 2> tgc_init = {
 | 
					 | 
				
			||||||
        iss_factory::instance().register_creator("tgc5c|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::tgc5c>>(cc);
 | 
					 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        iss_factory::instance().register_creator("tgc5c|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::tgc5c>>(cc);
 | 
					 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,14 +11,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <scc/report.h>
 | 
					#include <scc/report.h>
 | 
				
			||||||
#include <util/ities.h>
 | 
					#include <util/ities.h>
 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/iss.h>
 | 
				
			||||||
#include <iss/vm_types.h>
 | 
					#include <iss/vm_types.h>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace sysc {
 | 
					
 | 
				
			||||||
template<typename PLAT>
 | 
					template<typename PLAT>
 | 
				
			||||||
class sc_core_adapter : public PLAT, public sc_core_adapter_if {
 | 
					class sc_core_adapter : public PLAT {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    using reg_t       = typename iss::arch::traits<typename PLAT::core>::reg_t;
 | 
					    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 phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
 | 
				
			||||||
@@ -26,17 +26,13 @@ public:
 | 
				
			|||||||
    sc_core_adapter(sysc::tgfs::core_complex *owner)
 | 
					    sc_core_adapter(sysc::tgfs::core_complex *owner)
 | 
				
			||||||
    : owner(owner) { }
 | 
					    : owner(owner) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    iss::arch_if* get_arch_if() override { return this;}
 | 
					    uint32_t get_mode() { return this->reg.PRIV; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void set_mhartid(unsigned id) override { PLAT::set_mhartid(id); }
 | 
					    inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t get_mode() override { return this->reg.PRIV; }
 | 
					    inline bool get_interrupt_execution() { return this->interrupt_sim; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void set_interrupt_execution(bool v) override { this->interrupt_sim = v?1:0; }
 | 
					    heart_state_t &get_state() { return this->state; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    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 {
 | 
					    void notify_phase(iss::arch_if::exec_phase p) override {
 | 
				
			||||||
        if (p == iss::arch_if::ISTART)
 | 
					        if (p == iss::arch_if::ISTART)
 | 
				
			||||||
@@ -117,7 +113,7 @@ public:
 | 
				
			|||||||
        PLAT::wait_until(flags);
 | 
					        PLAT::wait_until(flags);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void local_irq(short id, bool value) override {
 | 
					    void local_irq(short id, bool value) {
 | 
				
			||||||
        reg_t mask = 0;
 | 
					        reg_t mask = 0;
 | 
				
			||||||
        switch (id) {
 | 
					        switch (id) {
 | 
				
			||||||
        case 3: // SW
 | 
					        case 3: // SW
 | 
				
			||||||
@@ -147,5 +143,6 @@ private:
 | 
				
			|||||||
    sysc::tgfs::core_complex *const owner;
 | 
					    sysc::tgfs::core_complex *const owner;
 | 
				
			||||||
    sc_core::sc_event wfi_evt;
 | 
					    sc_core::sc_event wfi_evt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
 | 
					#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * 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_ */
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2674
									
								
								src/vm/interp/vm_tgc_c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2674
									
								
								src/vm/interp/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
											
										
									
								
							
							
								
								
									
										4163
									
								
								src/vm/llvm/vm_tgc_c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4163
									
								
								src/vm/llvm/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
											
										
									
								
							
		Reference in New Issue
	
	Block a user