Compare commits
116 Commits
d43b35949e
...
d5fa47ef7f
Author | SHA1 | Date | |
---|---|---|---|
d5fa47ef7f | |||
d31b4ef5a8 | |||
7452c5df43 | |||
43d7b99905 | |||
f90c48e881 | |||
2d7973520b | |||
fd98ad95f6 | |||
bfa8166223 | |||
c42e336509 | |||
49d09a05d7 | |||
459794b863 | |||
039746112b | |||
ac6d7ea5d4 | |||
a89f00da19 | |||
ff04ee7807 | |||
8b6e3abd23 | |||
1616f0ac90 | |||
a20f39e847 | |||
334d3fb296 | |||
eb2ca33e5a | |||
0ea4cba1ca | |||
1d13c8196e | |||
ee6e1d4092 | |||
c8679fca85 | |||
f0ada1ba8c | |||
b17682e50e | |||
5866acf565 | |||
6acf73a40f | |||
2f15d9676e | |||
d78fcc48e5 | |||
4186723d37 | |||
17ee7b138d | |||
aa84a27a5b | |||
438e598a4a | |||
174259155d | |||
ba9339a50d | |||
65b4db5eca | |||
0fd82f1f3c | |||
a3084456fd | |||
09b01af3fa | |||
9c8b72693e | |||
c409e7b7ca | |||
2f05083cf0 | |||
e934049dd4 | |||
94f796ebdb | |||
836ba269e3 | |||
c8681096be | |||
adeffe47ad | |||
d95846a849 | |||
af887c286f | |||
4ddf50162c | |||
da819d8890 | |||
5ef5d57d30 | |||
d7bddd825c | |||
15f46a87db | |||
fc1ae4d57d | |||
d0f3a120fd | |||
c592a26346 | |||
e68918c2e8 | |||
473f8a5a17 | |||
2f4b5bd9b2 | |||
23b9741adf | |||
5d8da08ce5 | |||
a249aea703 | |||
e432dd8208 | |||
8c385647dd | |||
aaceecd5dc | |||
4b3f5a6b0c | |||
d41e1d816a | |||
a35974c9f5 | |||
9c456ba8f2 | |||
c57884caee | |||
cf7b62a3f9 | |||
f2bf6d682a | |||
a1fa8877f7 | |||
391f9bb808 | |||
ef02dba8c5 | |||
2f4cfb68dc | |||
7009943106 | |||
0a76ccbdac | |||
32e4aa83b8 | |||
78c7064295 | |||
412a4bd9bb | |||
ea3ff3c0cd | |||
b0bcb7febb | |||
c941890901 | |||
51fbc34fb3 | |||
4e0f20eba0 | |||
ff3fa19208 | |||
80057eef32 | |||
a5186ff88d | |||
f4ec21007b | |||
ac8eab6e25 | |||
b7c0fb2b1c | |||
768716b064 | |||
bea0dcc387 | |||
a6691bcd3c | |||
40db74ce02 | |||
c171e3c1ba | |||
c251fe15d5 | |||
dae8acb8a3 | |||
f7cec99fa6 | |||
be0e7db185 | |||
4aa26b85a0 | |||
9534d58d01 | |||
1668df0531 | |||
d8e009c72b | |||
d07c8679ed | |||
3d5b61f301 | |||
337f1634c0 | |||
72b09472d5 | |||
3261055871 | |||
34bb8e62ae | |||
da7e29fbb7 | |||
c4da47cedd | |||
ab554539e3 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,3 +31,4 @@ language.settings.xml
|
||||
/*.out
|
||||
/dump.json
|
||||
/src-gen/
|
||||
/*.yaml
|
||||
|
223
CMakeLists.txt
223
CMakeLists.txt
@ -1,20 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project("tgfs" VERSION 1.0.0)
|
||||
###############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
project(dbt-rise-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
conan_basic_setup()
|
||||
find_package(elfio)
|
||||
|
||||
find_package(Boost COMPONENTS program_options system thread filesystem 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)
|
||||
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)
|
||||
@ -27,96 +28,148 @@ endif()
|
||||
add_subdirectory(softfloat)
|
||||
|
||||
# library files
|
||||
FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h)
|
||||
set(LIB_HEADERS tgfscVSCHeaders} )
|
||||
FILE(GLOB TGC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
|
||||
)
|
||||
set(LIB_SOURCES
|
||||
src/iss/tgf_b.cpp
|
||||
src/iss/tgf_c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
src/vm/tcc/vm_tgf_b.cpp
|
||||
src/vm/tcc/vm_tgf_c.cpp
|
||||
src/vm/interp/vm_tgf_b.cpp
|
||||
src/vm/interp/vm_tgf_c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
src/plugin/instruction_count.cpp
|
||||
src/plugin/cycle_estimate.cpp
|
||||
${TGC_SOURCES}
|
||||
)
|
||||
|
||||
if(WITH_LLVM)
|
||||
set(LIB_SOURCES ${LIB_SOURCES}
|
||||
src/vm/llvm/fp_impl.cpp
|
||||
src/vm/llvm/vm_tgf_b.cpp
|
||||
src/vm/llvm/vm_tgf_c.cpp
|
||||
)
|
||||
FILE(GLOB TGC_LLVM_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/llvm/vm_*.cpp
|
||||
)
|
||||
list(APPEND LIB_SOURCES ${TGC_LLVM_SOURCES})
|
||||
endif()
|
||||
|
||||
if(WITH_TCC)
|
||||
FILE(GLOB TGC_TCC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
|
||||
)
|
||||
list(APPEND LIB_SOURCES ${TGC_TCC_SOURCES})
|
||||
endif()
|
||||
|
||||
# Define the library
|
||||
add_library(tgfs SHARED ${LIB_SOURCES})
|
||||
target_compile_options(tgfs PRIVATE -Wno-shift-count-overflow)
|
||||
target_include_directories(tgfs PUBLIC incl)
|
||||
target_link_libraries(tgfs PUBLIC softfloat scc-util)
|
||||
target_link_libraries(tgfs PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
||||
set_target_properties(tgfs PROPERTIES
|
||||
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")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC incl)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-core)
|
||||
endif()
|
||||
if(TARGET CONAN_PKG::elfio)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC CONAN_PKG::elfio)
|
||||
elseif(TARGET elfio::elfio)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
|
||||
else()
|
||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
|
||||
)
|
||||
|
||||
if(SystemC_FOUND)
|
||||
add_library(tgfs_sc src/sysc/core_complex.cpp)
|
||||
target_compile_definitions(tgfs_sc PUBLIC WITH_SYSTEMC)
|
||||
target_include_directories(tgfs_sc PUBLIC ../incl ${SystemC_INCLUDE_DIRS} ${CCI_INCLUDE_DIRS})
|
||||
|
||||
if(SCV_FOUND)
|
||||
target_compile_definitions(tgfs_sc PUBLIC WITH_SCV)
|
||||
target_include_directories(tgfs_sc PUBLIC ${SCV_INCLUDE_DIRS})
|
||||
endif()
|
||||
target_link_libraries(tgfs_sc PUBLIC tgfs scc )
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(tgfs_sc PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
target_link_libraries(tgfs_sc PUBLIC ${Boost_LIBRARIES} )
|
||||
set_target_properties(tgfs_sc PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
|
||||
)
|
||||
endif()
|
||||
|
||||
project("tgfs-sim")
|
||||
add_executable(tgfs-sim src/main.cpp)
|
||||
# This sets the include directory for the reference project. This is the -I flag in gcc.
|
||||
|
||||
if(WITH_LLVM)
|
||||
target_compile_definitions(tgfs-sim PRIVATE WITH_LLVM)
|
||||
target_link_libraries(tgfs-sim PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
# Links the target exe against the libraries
|
||||
target_link_libraries(tgfs-sim tgfs)
|
||||
target_link_libraries(tgfs-sim jsoncpp)
|
||||
target_link_libraries(tgfs-sim ${Boost_LIBRARIES} )
|
||||
if (Tcmalloc_FOUND)
|
||||
target_link_libraries(tgfs-sim ${Tcmalloc_LIBRARIES})
|
||||
endif(Tcmalloc_FOUND)
|
||||
|
||||
install(TARGETS tgfs tgfs-sim
|
||||
install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libs # binaries
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib
|
||||
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT devel # headers for mac (note the different component -> different package)
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
|
||||
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
|
||||
)
|
||||
|
||||
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory
|
||||
FILES_MATCHING # install only matched files
|
||||
PATTERN "*.h" # select header files
|
||||
)
|
||||
###############################################################################
|
||||
#
|
||||
# SYSTEM PACKAGING (RPM, TGZ, ...)
|
||||
# _____________________________________________________________________________
|
||||
###############################################################################
|
||||
project(tgc-sim)
|
||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||
|
||||
#include(CPackConfig)
|
||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||
# This sets the include directory for the reference project. This is the -I flag in gcc.
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
if(WITH_LLVM)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
# Links the target exe against the libraries
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
|
||||
if(TARGET Boost::program_options)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY})
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
|
||||
if (Tcmalloc_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
|
||||
endif(Tcmalloc_FOUND)
|
||||
|
||||
install(TARGETS tgc-sim
|
||||
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
|
||||
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
|
||||
)
|
||||
###############################################################################
|
||||
#
|
||||
# CMAKE PACKAGING (for other CMake projects to use this one easily)
|
||||
# _____________________________________________________________________________
|
||||
###############################################################################
|
||||
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
||||
|
||||
include(SystemCPackage)
|
||||
if(SystemC_FOUND)
|
||||
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_B)
|
||||
endif()
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_C)
|
||||
endif()
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_D)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
|
||||
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/core_complex.h)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
|
||||
)
|
||||
install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
|
||||
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package)
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
|
||||
)
|
||||
endif()
|
||||
|
||||
#include(PackageConfigurator)
|
30
contrib/build.tcl
Normal file
30
contrib/build.tcl
Normal file
@ -0,0 +1,30 @@
|
||||
namespace eval Specification {
|
||||
proc buildproc { args } {
|
||||
global env
|
||||
variable installDir
|
||||
variable compiler
|
||||
variable compiler [::scsh::get_backend_compiler]
|
||||
# set target $machine
|
||||
set target [::scsh::machine]
|
||||
set linkerOptions ""
|
||||
set preprocessorOptions ""
|
||||
set libversion $compiler
|
||||
switch -exact -- $target {
|
||||
"linux" {
|
||||
set install_dir $::env(TGFS_INSTALL_ROOT)
|
||||
set incldir "${install_dir}/include"
|
||||
set libdir "${install_dir}/lib64"
|
||||
set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"]
|
||||
# Set the Linker paths.
|
||||
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc"]
|
||||
}
|
||||
default {
|
||||
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"
|
||||
return
|
||||
}
|
||||
}
|
||||
::scsh::cwr_append_ipsimbld_opts preprocessor "$preprocessorOptions"
|
||||
::scsh::cwr_append_ipsimbld_opts linker "$linkerOptions"
|
||||
}
|
||||
::scsh::add_build_callback [namespace current]::buildproc
|
||||
}
|
4
contrib/tgc_import.cc
Normal file
4
contrib/tgc_import.cc
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
#include "sysc/core_complex.h"
|
||||
|
||||
void modules() { sysc::tgfs::core_complex i_core_complex("core_complex"); }
|
50
contrib/tgc_import.tcl
Normal file
50
contrib/tgc_import.tcl
Normal file
@ -0,0 +1,50 @@
|
||||
#############################################################################
|
||||
#
|
||||
#############################################################################
|
||||
proc getScriptDirectory {} {
|
||||
set dispScriptFile [file normalize [info script]]
|
||||
set scriptFolder [file dirname $dispScriptFile]
|
||||
return $scriptFolder
|
||||
}
|
||||
if { $::env(SNPS_VP_PRODUCT) == "PAULTRA" } {
|
||||
set hardware /HARDWARE/HW/HW
|
||||
} else {
|
||||
set hardware /HARDWARE
|
||||
}
|
||||
|
||||
set scriptDir [getScriptDirectory]
|
||||
set top_design_name core_complex
|
||||
set clocks clk_i
|
||||
set resets rst_i
|
||||
set model_prefix "i_"
|
||||
set model_postfix ""
|
||||
|
||||
::pct::new_project
|
||||
::pct::open_library TLM2_PL
|
||||
::pct::clear_systemc_defines
|
||||
::pct::clear_systemc_include_path
|
||||
::pct::add_to_systemc_include_path $::env(TGFS_INSTALL_ROOT)/include
|
||||
::pct::set_import_protocol_generation_flag false
|
||||
::pct::set_update_existing_encaps_flag true
|
||||
::pct::set_dynamic_port_arrays_flag true
|
||||
::pct::set_import_scml_properties_flag true
|
||||
::pct::load_modules --set-category modules tgc_import.cc
|
||||
|
||||
# Set Port Protocols correctly
|
||||
set block ${top_design_name}
|
||||
foreach clock ${clocks} {
|
||||
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${clock} SYSTEM_LIBRARY:CLOCK
|
||||
}
|
||||
foreach reset ${resets} {
|
||||
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET
|
||||
}
|
||||
::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16
|
||||
|
||||
# Set compile settings and look
|
||||
set block SYSTEM_LIBRARY:${top_design_name}
|
||||
::pct::set_encap_build_script $block/${top_design_name} $scriptDir/build.tcl
|
||||
::pct::set_background_color_rgb $block 255 255 255 255
|
||||
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${top_design_name}
|
||||
|
||||
# export the result as component
|
||||
::pct::export_system_library ${top_design_name} ${top_design_name}.xml
|
Submodule gen_input/CoreDSL-Instruction-Set-Description updated: 3bb3763e92...b005607fc3
14
gen_input/TGC_B.core_desc
Normal file
14
gen_input/TGC_B.core_desc
Normal file
@ -0,0 +1,14 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
Core TGC_B provides RV32I, Zicsr, Zifencei {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000000000100000000;
|
||||
unsigned MARCHID_VAL = 0x80000002;
|
||||
}
|
||||
}
|
||||
|
13
gen_input/TGC_C.core_desc
Normal file
13
gen_input/TGC_C.core_desc
Normal file
@ -0,0 +1,13 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000001000100000100;
|
||||
unsigned MARCHID_VAL = 0x80000003;
|
||||
}
|
||||
}
|
13
gen_input/TGC_D.core_desc
Normal file
13
gen_input/TGC_D.core_desc
Normal file
@ -0,0 +1,13 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
Core TGC_D provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000100000011000100000100;
|
||||
unsigned MARCHID_VAL = 0x80000004;
|
||||
}
|
||||
}
|
73
gen_input/TGC_D_XRB_MAC.core_desc
Normal file
73
gen_input/TGC_D_XRB_MAC.core_desc
Normal file
@ -0,0 +1,73 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RISCVBase.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
InstructionSet X_RB_MAC extends RISCVBase {
|
||||
architectural_state {
|
||||
register unsigned<64> ACC;
|
||||
}
|
||||
|
||||
instructions {
|
||||
RESET_ACC { // v-- funct7 v-- funct3
|
||||
encoding: 7'd0 :: 10'b0 :: 3'd0 :: 5'b0 :: 7'b0001011;
|
||||
behavior: ACC = 0;
|
||||
}
|
||||
|
||||
GET_ACC_LO {
|
||||
encoding: 7'd1 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
|
||||
behavior: if (rd != 0) X[rd] = ACC[31:0];
|
||||
}
|
||||
|
||||
GET_ACC_HI {
|
||||
encoding: 7'd2 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
|
||||
behavior: if (rd != 0) X[rd] = ACC[63:32];
|
||||
}
|
||||
|
||||
MACU_32 {
|
||||
encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
|
||||
behavior: {
|
||||
unsigned<64> mul = X[rs1] * X[rs2];
|
||||
unsigned<33> add = mul[31:0] + ACC[31:0];
|
||||
ACC = add[31:0];
|
||||
}
|
||||
}
|
||||
|
||||
MACS_32 {
|
||||
encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
|
||||
behavior: {
|
||||
signed<64> mul = ((signed) X[rs1]) * ((signed) X[rs2]);
|
||||
signed<33> add = ((signed) mul[31:0]) + ((signed) ACC[31:0]);
|
||||
ACC = add[31:0]; // bit range always yields unsigned type
|
||||
}
|
||||
}
|
||||
|
||||
MACU_64 {
|
||||
encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
|
||||
behavior: {
|
||||
unsigned<64> mul = X[rs1] * X[rs2];
|
||||
unsigned<65> add = mul + ACC;
|
||||
ACC = add[63:0];
|
||||
}
|
||||
}
|
||||
|
||||
MACS_64 {
|
||||
encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
|
||||
behavior: {
|
||||
signed<64> mul = ((signed) X[rs1]) * ((signed) X[rs2]);
|
||||
signed<65> add = mul + ((signed) ACC);
|
||||
ACC = add[63:0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core TGC_D_XRB_MAC provides RV32I, Zicsr, Zifencei, RV32M, RV32IC, X_RB_MAC {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000001000100000100;
|
||||
unsigned MARCHID_VAL = 0x80000004;
|
||||
}
|
||||
}
|
133
gen_input/TGC_D_XRB_NN.core_desc
Normal file
133
gen_input/TGC_D_XRB_NN.core_desc
Normal file
@ -0,0 +1,133 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RISCVBase.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
InstructionSet X_RB_NN extends RISCVBase {
|
||||
|
||||
instructions {
|
||||
|
||||
// signed saturate with pre-shift
|
||||
SSAT {
|
||||
// instruction format: R-type
|
||||
// opcode space: custom-1 (inst[6:2] = 01010)
|
||||
// opcode = 0b0101011, func3 = 0b000, func7 = <bit position to saturate to>
|
||||
encoding: sat_bit_pos[6:0] :: rs2[4:0] :: rs1[4:0] :: 0b000 :: rd[4:0] :: 0b0101011;
|
||||
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}, {name(sat_bit_pos)}";
|
||||
behavior: {
|
||||
signed<XLEN> val_s = (signed<XLEN>)X[rs1];
|
||||
unsigned<XLEN> pre_shift = (unsigned<XLEN>)X[rs2];
|
||||
unsigned<XLEN> sat_limit;
|
||||
signed<XLEN> upper_limit;
|
||||
signed<XLEN> lower_limit;
|
||||
|
||||
if((rd != 0) && (sat_bit_pos > 0) && (sat_bit_pos <= 32) && (pre_shift < 32)) {
|
||||
sat_limit = (unsigned<XLEN>)(1 << (sat_bit_pos - 1));
|
||||
upper_limit = (signed)sat_limit - 1;
|
||||
lower_limit = (signed)sat_limit * (-1);
|
||||
|
||||
// important: arithmetical shift right
|
||||
val_s = val_s >> pre_shift;
|
||||
X[rd] = (val_s > upper_limit) ? (upper_limit) : ( (val_s < lower_limit) ? (lower_limit) : (val_s) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom packed dot product with accumulation (4x8bit)
|
||||
PDOT8 {
|
||||
// instruction format: R-type
|
||||
// opcode space: custom-1 (inst[6:2] = 01010)
|
||||
// opcode = 0b0101011, func3 = 0b001, func7 = 0b0000000
|
||||
encoding: 0b0000000 :: rs2[4:0] :: rs1[4:0] :: 0b001 :: rd[4:0] :: 0b0101011;
|
||||
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
|
||||
behavior: {
|
||||
signed<8> op1_0 = (signed<8>)X[rs1][ 7: 0];
|
||||
signed<8> op1_1 = (signed<8>)X[rs1][15: 8];
|
||||
signed<8> op1_2 = (signed<8>)X[rs1][23:16];
|
||||
signed<8> op1_3 = (signed<8>)X[rs1][31:24];
|
||||
|
||||
signed<8> op2_0 = (signed<8>)X[rs2][ 7: 0];
|
||||
signed<8> op2_1 = (signed<8>)X[rs2][15: 8];
|
||||
signed<8> op2_2 = (signed<8>)X[rs2][23:16];
|
||||
signed<8> op2_3 = (signed<8>)X[rs2][31:24];
|
||||
|
||||
signed<XLEN> op3 = (signed<XLEN>)X[rd];
|
||||
|
||||
signed<16> mul0 = op1_0 * op2_0;
|
||||
signed<16> mul1 = op1_1 * op2_1;
|
||||
signed<16> mul2 = op1_2 * op2_2;
|
||||
signed<16> mul3 = op1_3 * op2_3;
|
||||
|
||||
signed<19> sum_tmp = mul0 + mul1 + mul2 + mul3;
|
||||
|
||||
signed<33> result = op3 + sum_tmp;
|
||||
|
||||
if(rd != 0) X[rd] = result[31:0];
|
||||
}
|
||||
}
|
||||
|
||||
// standard signed multiply accumulate with 32 bit operands and 32 bit result
|
||||
MAC {
|
||||
// instruction format: R-type
|
||||
// opcode space: custom-1 (inst[6:2] = 01010)
|
||||
// opcode = 0b0101011, func3 = 0b010, func7 = 0b0000000
|
||||
encoding: 0b0000000 :: rs2[4:0] :: rs1[4:0] :: 0b010 :: rd[4:0] :: 0b0101011;
|
||||
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
|
||||
behavior: {
|
||||
signed<65> result = (signed)X[rs1] * (signed)X[rs2] + (signed)X[rd];
|
||||
if(rd != 0) X[rd] = result[31:0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// WARNING: The following two HW loop instructions are not fully specified or implemented. The idea is to design the HW loops identical to the RI5CY core (current naming: CV32E40P)
|
||||
// See "Short Hardware Loop Setup Instructions" from RI5CY specification document from April 2019, revision 4.0: https://www.pulp-platform.org/docs/ri5cy_user_manual.pdf -> page 38, chapter 14.2
|
||||
// Specific CSRs are introduced to support the HW loops (see page 17, chapter 7).
|
||||
|
||||
// lp.setup HW loop (Short Hardware Loop Setup Instruction)
|
||||
LOOP {
|
||||
// instruction format: I-type
|
||||
// opcode space: custom-3 (inst[6:2] = 11110)
|
||||
// opcode = 0b1111011, func3 = 0b100
|
||||
// uimmL[11:0] src1 100 0000 L 111 1011 -> lp.setup L,rs1, uimmL
|
||||
encoding: imm[11:0] :: rs1[4:0] :: 0b100 :: 0b0000 :: L[0:0] :: 0b1111011;
|
||||
args_disass:"{name(L)}, {name(rs1)}, {imm}";
|
||||
behavior: {
|
||||
// L: loop level (two loop levels would be sufficient); L=0 has higher priority and is considered as the inner loop.
|
||||
/*
|
||||
lpstart[L] = PC + 4;
|
||||
lpend[L] = PC + ((unsigned<12>)imm << 1);
|
||||
lpcount[L] = rs1;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// lp.setupi HW loop (Short Hardware Loop Setup Instruction with immediate value for loop count)
|
||||
LOOPI {
|
||||
// instruction format: I-type
|
||||
// opcode space: custom-3 (inst[6:2] = 11110)
|
||||
// opcode = 0b1111011, func3 = 0b101
|
||||
// uimmL[11:0] uimmS[4:0] 101 0000 L 111 1011 -> lp.setupi L, uimmS, uimmL
|
||||
encoding: imm2[11:0] :: imm1[4:0] :: 0b101 :: 0b0000 :: L[0:0] :: 0b1111011;
|
||||
args_disass:"{name(L)}, {imm1}, {imm2}";
|
||||
behavior: {
|
||||
// L: loop level (two loop levels would be sufficient); L=0 has higher priority and is considered as the inner loop.
|
||||
/*
|
||||
lpstart[L] = PC + 4;
|
||||
lpend[L] = PC + ((unsigned<5>)imm1 << 1);
|
||||
lpcount[L] = (unsigned<12>)imm2;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core TGC_D_XRB_NN provides RV32I, Zicsr, Zifencei, RV32M, RV32IC, X_RB_NN {
|
||||
architectural_state {
|
||||
XLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000100100000011000100000100;
|
||||
unsigned MARCHID_VAL = 0x80000004;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
|
||||
Core TGF_B provides RV32I {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000000000000000100000000;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core TGF_C provides RV32I, RV32M, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000000000001000100000100;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
import "RV32I.core_desc"
|
||||
import "RV64I.core_desc"
|
||||
import "RVM.core_desc"
|
||||
import "RVA.core_desc"
|
||||
import "RVC.core_desc"
|
||||
import "RVF.core_desc"
|
||||
import "RVD.core_desc"
|
||||
|
||||
|
||||
Core MNRV32 provides RV32I, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100000101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100000101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV32GC provides RV32I, RV32M, RV32A, RV32F, RV32D, RV32IC, RV32FC, RV32DC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
FLEN:=64;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100101101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV64I provides RV64I {
|
||||
constants {
|
||||
XLEN:=64;
|
||||
PCLEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b10000000000001000000000100000000;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV64GC provides RV64I, RV64M, RV64A, RV64F, RV64D, RV32FC, RV32DC, RV64IC {
|
||||
constants {
|
||||
XLEN:=64;
|
||||
FLEN:=64;
|
||||
PCLEN:=64;
|
||||
MUL_LEN:=128;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100101101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,43 +29,12 @@
|
||||
* 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()
|
||||
<%
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{it.size}
|
||||
regs[-1]=64 // correct for NEXT_PC
|
||||
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
||||
return regs
|
||||
}
|
||||
%>
|
||||
#include "util/ities.h"
|
||||
@ -77,10 +46,10 @@ def getRegisterAliasNames(){
|
||||
|
||||
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;
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
|
||||
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
|
||||
reg.icount = 0;
|
||||
@ -89,11 +58,13 @@ ${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
|
||||
${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));
|
||||
auto base_ptr = reinterpret_cast<traits<${coreDef.name.toLowerCase()}>::reg_t*>(get_regs_base_ptr());
|
||||
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i)
|
||||
*(base_ptr+i)=0;
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,47 +29,38 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
<%
|
||||
import com.minres.coredsl.coreDsl.Register
|
||||
import com.minres.coredsl.coreDsl.RegisterFile
|
||||
import com.minres.coredsl.coreDsl.RegisterAlias
|
||||
def getTypeSize(size){
|
||||
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
def getOriginalName(reg){
|
||||
if( reg.original instanceof RegisterFile) {
|
||||
if( reg.index != null ) {
|
||||
return reg.original.name+generator.generateHostCode(reg.index)
|
||||
} else {
|
||||
return reg.original.name
|
||||
}
|
||||
} else if(reg.original instanceof Register){
|
||||
return reg.original.name
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{nativeTypeSize(it.size)}
|
||||
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
||||
return regs
|
||||
}
|
||||
def getRegisterOffsets(){
|
||||
def offset = 0
|
||||
def offsets = []
|
||||
getRegisterSizes().each { size ->
|
||||
offsets<<offset
|
||||
offset+=size/8
|
||||
}
|
||||
return offsets
|
||||
}
|
||||
def getRegisterNames(){
|
||||
def regNames = []
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{
|
||||
regNames+=reg.name.toLowerCase()+it
|
||||
}
|
||||
} else if(reg instanceof Register){
|
||||
regNames+=reg.name.toLowerCase()
|
||||
}
|
||||
}
|
||||
return regNames
|
||||
def byteSize(int size){
|
||||
if(size<=8) return 8;
|
||||
if(size<=16) return 16;
|
||||
if(size<=32) return 32;
|
||||
if(size<=64) return 64;
|
||||
return 128;
|
||||
}
|
||||
def getRegisterAliasNames(){
|
||||
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
|
||||
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
|
||||
} else if(reg instanceof Register){
|
||||
regMap[reg.name]?:reg.name.toLowerCase()
|
||||
}
|
||||
}.flatten()
|
||||
def getCString(def val){
|
||||
if(val instanceof BigIntegerWithRadix)
|
||||
return ((BigIntegerWithRadix)val).toCString()
|
||||
else
|
||||
return val.toString()
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
@ -87,43 +78,28 @@ struct ${coreDef.name.toLowerCase()};
|
||||
|
||||
template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
|
||||
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
|
||||
{"${getRegisterNames().join("\", \"")}"}};
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_names{
|
||||
{"${registers.collect{it.name}.join('", "')}"}};
|
||||
|
||||
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
|
||||
{"${getRegisterAliasNames().join("\", \"")}"}};
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_aliases{
|
||||
{"${registers.collect{it.alias}.join('", "')}"}};
|
||||
|
||||
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
|
||||
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
|
||||
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
||||
|
||||
enum reg_e {<%
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{%>
|
||||
${reg.name}${it},<%
|
||||
}
|
||||
} else if(reg instanceof Register){ %>
|
||||
${reg.name},<%
|
||||
}
|
||||
}%>
|
||||
NUM_REGS,
|
||||
NEXT_${pc.name}=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
enum reg_e {
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT<%
|
||||
allRegs.each { reg ->
|
||||
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
|
||||
${reg.name} = ${aliasname}<%
|
||||
}
|
||||
}%>
|
||||
ICOUNT,
|
||||
CYCLE,
|
||||
INSTRET
|
||||
};
|
||||
|
||||
using reg_t = uint${regDataWidth}_t;
|
||||
using reg_t = uint${addrDataWidth}_t;
|
||||
|
||||
using addr_t = uint${addrDataWidth}_t;
|
||||
|
||||
@ -133,17 +109,22 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
|
||||
{${regSizes.join(",")}}};
|
||||
static constexpr std::array<const uint32_t, ${getRegisterSizes().size}> reg_bit_widths{
|
||||
{${getRegisterSizes().join(',')}}};
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
|
||||
{${regOffsets.join(",")}}};
|
||||
static constexpr std::array<const uint32_t, ${getRegisterOffsets().size}> reg_byte_offsets{
|
||||
{${getRegisterOffsets().join(',')}}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
|
||||
|
||||
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
|
||||
${instr.instruction.name} = ${index},<%}%>
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
|
||||
struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
@ -159,14 +140,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
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; }
|
||||
|
||||
@ -189,32 +162,29 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
struct ${coreDef.name}_regs {<%
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{%>
|
||||
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
|
||||
}
|
||||
} else if(reg instanceof Register){ %>
|
||||
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
|
||||
}
|
||||
}%>
|
||||
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
registers.each { reg -> if(reg.size>0) {%>
|
||||
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
|
||||
}}%>
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
|
||||
#pragma pack(pop)
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
<%
|
||||
def fcsr = allRegs.find {it.name=='FCSR'}
|
||||
def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
|
||||
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
|
||||
uint${fcsr.size}_t get_fcsr(){return reg.FCSR;}
|
||||
void set_fcsr(uint${fcsr.size}_t val){reg.FCSR = val;}
|
||||
<%} else { %>
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
<%}%>
|
||||
};
|
||||
|
16
gen_input/templates/CORENAME_instr.yaml.gtl
Normal file
16
gen_input/templates/CORENAME_instr.yaml.gtl
Normal file
@ -0,0 +1,16 @@
|
||||
<% def getInstructionGroups() {
|
||||
def instrGroups = [:]
|
||||
instructions.each {
|
||||
def groupName = it['instruction'].eContainer().name
|
||||
if(!instrGroups.containsKey(groupName)) {
|
||||
instrGroups[groupName]=[]
|
||||
}
|
||||
instrGroups[groupName]+=it;
|
||||
}
|
||||
instrGroups
|
||||
}%><%getInstructionGroups().each{name, instrList -> %>
|
||||
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
|
||||
- ${it.instruction.name}:
|
||||
encoding: ${it.encoding}
|
||||
mask: ${it.mask}<%}}%>
|
||||
|
352
gen_input/templates/interp/CORENAME.cpp.gtl
Normal file
352
gen_input/templates/interp/CORENAME.cpp.gtl
Normal file
@ -0,0 +1,352 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
%>
|
||||
#include "../fp_functions.h"
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/interp/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <array>
|
||||
#include <iss/debugger/riscv_target_adapter.h>
|
||||
|
||||
namespace iss {
|
||||
namespace interp {
|
||||
namespace ${coreDef.name.toLowerCase()} {
|
||||
using namespace iss::arch;
|
||||
using namespace iss::debugger;
|
||||
|
||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
|
||||
public:
|
||||
using traits = arch::traits<ARCH>;
|
||||
using super = typename iss::interp::vm_base<ARCH>;
|
||||
using virt_addr_t = typename super::virt_addr_t;
|
||||
using phys_addr_t = typename super::phys_addr_t;
|
||||
using code_word_t = typename super::code_word_t;
|
||||
using addr_t = typename super::addr_t;
|
||||
using reg_t = typename traits::reg_t;
|
||||
using mem_type_e = typename traits::mem_type_e;
|
||||
|
||||
vm_impl();
|
||||
|
||||
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
|
||||
|
||||
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
|
||||
|
||||
target_adapter_if *accquire_target_adapter(server_if *srv) override {
|
||||
debugger_if::dbg_enabled = true;
|
||||
if (super::tgt_adapter == nullptr)
|
||||
super::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
|
||||
return super::tgt_adapter;
|
||||
}
|
||||
|
||||
protected:
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_ret_t = virt_addr_t;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
||||
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
compile_func decode_inst(code_word_t instr) ;
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
|
||||
// some compile time constants
|
||||
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
||||
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
|
||||
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
|
||||
enum {
|
||||
LUT_SIZE = 1 << util::bit_count(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;
|
||||
compile_func opc;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
|
||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
inline void leave(unsigned lvl){
|
||||
this->core.leave_trap(lvl);
|
||||
}
|
||||
|
||||
inline void wait(unsigned type){
|
||||
this->core.wait_until(type);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
|
||||
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint8_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint16_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint32_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint64_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||
inline S sext(U from) {
|
||||
auto mask = (1ULL<<W) - 1;
|
||||
auto sign_mask = 1ULL<<(W-1);
|
||||
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct InstructionDesriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name} */
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
|
||||
// pre execution stuff
|
||||
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
*PC=*NEXT_PC;
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
*trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */
|
||||
<%instr.disass.eachLine{%>${it}
|
||||
<%}%>
|
||||
}
|
||||
// used registers<%instr.usedVariables.each{ k,v->
|
||||
if(v.isArray) {%>
|
||||
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
|
||||
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
|
||||
<%}}%>// calculate next pc value
|
||||
*NEXT_PC = *PC + ${instr.length/8};
|
||||
// execute instruction
|
||||
try {
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>} catch(...){}
|
||||
// post execution stuff
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val, instr);
|
||||
} else {
|
||||
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++;
|
||||
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++;
|
||||
}
|
||||
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
|
||||
pc.val=*NEXT_PC;
|
||||
return pc;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
|
||||
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
// post execution stuff
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val, instr);
|
||||
}
|
||||
pc.val=*NEXT_PC;
|
||||
return pc;
|
||||
}
|
||||
|
||||
//static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||
auto phys_pc = this->core.v2p(pc);
|
||||
//if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
|
||||
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
|
||||
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
|
||||
//} else {
|
||||
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
|
||||
//}
|
||||
return iss::Ok;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
}
|
||||
|
||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
// according to
|
||||
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||
#ifdef __GCC__
|
||||
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
||||
#elif __cplusplus < 201402L
|
||||
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
||||
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
||||
#else
|
||||
constexpr size_t bit_count(uint32_t u) {
|
||||
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
for (auto instr : instr_descr) {
|
||||
auto quadrant = instr.value & 0x3;
|
||||
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
||||
}
|
||||
for(auto& lut: qlut){
|
||||
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
|
||||
return bit_count(a.mask) > bit_count(b.mask);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_count_limit_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT;
|
||||
}
|
||||
|
||||
inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
|
||||
for(auto& e: qlut[instr&0x3]){
|
||||
if(!((instr&e.mask) ^ e.value )) return e.opc;
|
||||
}
|
||||
return &this_class::illegal_intruction;
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
code_word_t insn = 0;
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
auto pc=start;
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||
auto res = fetch_ins(pc, data);
|
||||
if(res!=iss::Ok){
|
||||
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
|
||||
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
|
||||
} else {
|
||||
if (is_jump_to_self_enabled(cond) &&
|
||||
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto f = decode_inst(insn);
|
||||
auto old_pc = pc.val;
|
||||
pc = (this->*f)(pc, insn);
|
||||
}
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
} // namespace mnrv32
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||
return std::unique_ptr<vm_if>(ret);
|
||||
}
|
||||
} // namespace interp
|
||||
} // namespace iss
|
@ -1,247 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2020 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "../fp_functions.h"
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/interp/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <array>
|
||||
#include <iss/debugger/riscv_target_adapter.h>
|
||||
|
||||
namespace iss {
|
||||
namespace interp {
|
||||
namespace ${coreDef.name.toLowerCase()} {
|
||||
using namespace iss::arch;
|
||||
using namespace iss::debugger;
|
||||
|
||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
|
||||
public:
|
||||
using super = typename iss::interp::vm_base<ARCH>;
|
||||
using virt_addr_t = typename super::virt_addr_t;
|
||||
using phys_addr_t = typename super::phys_addr_t;
|
||||
using code_word_t = typename super::code_word_t;
|
||||
using addr_t = typename super::addr_t;
|
||||
using reg_t = typename traits<ARCH>::reg_t;
|
||||
using iss::interp::vm_base<ARCH>::get_reg;
|
||||
|
||||
vm_impl();
|
||||
|
||||
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
|
||||
|
||||
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
|
||||
|
||||
target_adapter_if *accquire_target_adapter(server_if *srv) override {
|
||||
debugger_if::dbg_enabled = true;
|
||||
if (super::tgt_adapter == nullptr)
|
||||
super::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
|
||||
return super::tgt_adapter;
|
||||
}
|
||||
|
||||
protected:
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_ret_t = virt_addr_t;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
||||
|
||||
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
||||
|
||||
virt_addr_t execute_inst(virt_addr_t start, std::function<bool(void)> pred) override;
|
||||
|
||||
// some compile time constants
|
||||
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
||||
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
|
||||
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
|
||||
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
|
||||
|
||||
std::array<compile_func, LUT_SIZE> lut;
|
||||
|
||||
std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
|
||||
std::array<compile_func, LUT_SIZE> lut_11;
|
||||
|
||||
std::array<compile_func *, 4> qlut;
|
||||
|
||||
std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};
|
||||
|
||||
void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
|
||||
compile_func f) {
|
||||
if (pos < 0) {
|
||||
lut[idx] = f;
|
||||
} else {
|
||||
auto bitmask = 1UL << pos;
|
||||
if ((mask & bitmask) == 0) {
|
||||
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
|
||||
} else {
|
||||
if ((valid & bitmask) == 0) {
|
||||
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
|
||||
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
|
||||
} else {
|
||||
auto new_val = idx << 1;
|
||||
if ((value & bitmask) != 0) new_val++;
|
||||
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }
|
||||
|
||||
uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
|
||||
if (pos >= 0) {
|
||||
auto bitmask = 1UL << pos;
|
||||
if ((mask & bitmask) == 0) {
|
||||
lut_val = extract_fields(pos - 1, val, mask, lut_val);
|
||||
} else {
|
||||
auto new_val = lut_val << 1;
|
||||
if ((val & bitmask) != 0) new_val++;
|
||||
lut_val = extract_fields(pos - 1, val, mask, new_val);
|
||||
}
|
||||
}
|
||||
return lut_val;
|
||||
}
|
||||
|
||||
void raise_trap(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::TRAP_STATE) = trap_val;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
void leave_trap(unsigned lvl){
|
||||
this->core.leave_trap(lvl);
|
||||
auto pc_val = super::template read_mem<reg_t>(traits<ARCH>::CSR, (lvl << 8) + 0x41);
|
||||
this->template get_reg<reg_t>(arch::traits<ARCH>::NEXT_PC) = pc_val;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::LAST_BRANCH) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
void wait(unsigned type){
|
||||
this->core.wait_until(type);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct InstructionDesriptor {
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name} */
|
||||
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){<%instr.code.eachLine{%>
|
||||
${it}<%}%>
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
|
||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
return pc;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
}
|
||||
|
||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
qlut[0] = lut_00.data();
|
||||
qlut[1] = lut_01.data();
|
||||
qlut[2] = lut_10.data();
|
||||
qlut[3] = lut_11.data();
|
||||
for (auto instr : instr_descr) {
|
||||
auto quantrant = instr.value & 0x3;
|
||||
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(virt_addr_t start, std::function<bool(void)> pred) {
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
enum {TRAP_ID=1<<16};
|
||||
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
|
||||
code_word_t insn = 0;
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
auto pc=start;
|
||||
while(pred){
|
||||
auto paddr = this->core.v2p(pc);
|
||||
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
if ((insn & 0x3) == 0x3) // this is a 32bit instruction
|
||||
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
} else {
|
||||
if (this->core.read(paddr, 4, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
}
|
||||
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto lut_val = extract_fields(insn);
|
||||
auto f = qlut[insn & 0x3][lut_val];
|
||||
if (!f)
|
||||
f = &this_class::illegal_intruction;
|
||||
pc = (this->*f)(pc, insn);
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
} // namespace mnrv32
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||
return std::unique_ptr<vm_if>(ret);
|
||||
}
|
||||
} // namespace interp
|
||||
} // namespace iss
|
1
incl/iss/arch/.gitignore
vendored
Normal file
1
incl/iss/arch/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/tgc_*.h
|
245
incl/iss/arch/riscv_hart_common.h
Normal file
245
incl/iss/arch/riscv_hart_common.h
Normal file
@ -0,0 +1,245 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
* eyck@minres.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _RISCV_HART_COMMON
|
||||
#define _RISCV_HART_COMMON
|
||||
|
||||
#include "iss/arch_if.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
||||
|
||||
enum features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8};
|
||||
|
||||
enum riscv_csr {
|
||||
/* user-level CSR */
|
||||
// User Trap Setup
|
||||
ustatus = 0x000,
|
||||
uie = 0x004,
|
||||
utvec = 0x005,
|
||||
// User Trap Handling
|
||||
uscratch = 0x040,
|
||||
uepc = 0x041,
|
||||
ucause = 0x042,
|
||||
utval = 0x043,
|
||||
uip = 0x044,
|
||||
// User Floating-Point CSRs
|
||||
fflags = 0x001,
|
||||
frm = 0x002,
|
||||
fcsr = 0x003,
|
||||
// User Counter/Timers
|
||||
cycle = 0xC00,
|
||||
time = 0xC01,
|
||||
instret = 0xC02,
|
||||
hpmcounter3 = 0xC03,
|
||||
hpmcounter4 = 0xC04,
|
||||
/*...*/
|
||||
hpmcounter31 = 0xC1F,
|
||||
cycleh = 0xC80,
|
||||
timeh = 0xC81,
|
||||
instreth = 0xC82,
|
||||
hpmcounter3h = 0xC83,
|
||||
hpmcounter4h = 0xC84,
|
||||
/*...*/
|
||||
hpmcounter31h = 0xC9F,
|
||||
/* supervisor-level CSR */
|
||||
// Supervisor Trap Setup
|
||||
sstatus = 0x100,
|
||||
sedeleg = 0x102,
|
||||
sideleg = 0x103,
|
||||
sie = 0x104,
|
||||
stvec = 0x105,
|
||||
scounteren = 0x106,
|
||||
// Supervisor Trap Handling
|
||||
sscratch = 0x140,
|
||||
sepc = 0x141,
|
||||
scause = 0x142,
|
||||
stval = 0x143,
|
||||
sip = 0x144,
|
||||
// Supervisor Protection and Translation
|
||||
satp = 0x180,
|
||||
/* machine-level CSR */
|
||||
// Machine Information Registers
|
||||
mvendorid = 0xF11,
|
||||
marchid = 0xF12,
|
||||
mimpid = 0xF13,
|
||||
mhartid = 0xF14,
|
||||
// Machine Trap Setup
|
||||
mstatus = 0x300,
|
||||
misa = 0x301,
|
||||
medeleg = 0x302,
|
||||
mideleg = 0x303,
|
||||
mie = 0x304,
|
||||
mtvec = 0x305,
|
||||
mcounteren = 0x306,
|
||||
mtvt = 0x307, //CLIC
|
||||
// Machine Trap Handling
|
||||
mscratch = 0x340,
|
||||
mepc = 0x341,
|
||||
mcause = 0x342,
|
||||
mtval = 0x343,
|
||||
mip = 0x344,
|
||||
mxnti = 0x345, //CLIC
|
||||
mintstatus = 0x346, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||
mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
|
||||
mscratchcswl = 0x349, // MRW Conditional scratch swap on level change (CLIC)
|
||||
mintthresh = 0x350, // MRW Interrupt-level threshold (CLIC) - addr subject to change
|
||||
mclicbase = 0x351, // MRW Base address for CLIC memory mapped registers (CLIC) - addr subject to change
|
||||
// Physical Memory Protection
|
||||
pmpcfg0 = 0x3A0,
|
||||
pmpcfg1 = 0x3A1,
|
||||
pmpcfg2 = 0x3A2,
|
||||
pmpcfg3 = 0x3A3,
|
||||
pmpaddr0 = 0x3B0,
|
||||
pmpaddr1 = 0x3B1,
|
||||
pmpaddr2 = 0x3B2,
|
||||
pmpaddr3 = 0x3B3,
|
||||
pmpaddr4 = 0x3B4,
|
||||
pmpaddr5 = 0x3B5,
|
||||
pmpaddr6 = 0x3B6,
|
||||
pmpaddr7 = 0x3B7,
|
||||
pmpaddr8 = 0x3B8,
|
||||
pmpaddr9 = 0x3B9,
|
||||
pmpaddr10 = 0x3BA,
|
||||
pmpaddr11 = 0x3BB,
|
||||
pmpaddr12 = 0x3BC,
|
||||
pmpaddr13 = 0x3BD,
|
||||
pmpaddr14 = 0x3BE,
|
||||
pmpaddr15 = 0x3BF,
|
||||
// Machine Counter/Timers
|
||||
mcycle = 0xB00,
|
||||
minstret = 0xB02,
|
||||
mhpmcounter3 = 0xB03,
|
||||
mhpmcounter4 = 0xB04,
|
||||
/*...*/
|
||||
mhpmcounter31 = 0xB1F,
|
||||
mcycleh = 0xB80,
|
||||
minstreth = 0xB82,
|
||||
mhpmcounter3h = 0xB83,
|
||||
mhpmcounter4h = 0xB84,
|
||||
/*...*/
|
||||
mhpmcounter31h = 0xB9F,
|
||||
// Machine Counter Setup
|
||||
mhpmevent3 = 0x323,
|
||||
mhpmevent4 = 0x324,
|
||||
/*...*/
|
||||
mhpmevent31 = 0x33F,
|
||||
// Debug/Trace Registers (shared with Debug Mode)
|
||||
tselect = 0x7A0,
|
||||
tdata1 = 0x7A1,
|
||||
tdata2 = 0x7A2,
|
||||
tdata3 = 0x7A3,
|
||||
// Debug Mode Registers
|
||||
dcsr = 0x7B0,
|
||||
dpc = 0x7B1,
|
||||
dscratch0 = 0x7B2,
|
||||
dscratch1 = 0x7B3
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
PGSHIFT = 12,
|
||||
PTE_PPN_SHIFT = 10,
|
||||
// page table entry (PTE) fields
|
||||
PTE_V = 0x001, // Valid
|
||||
PTE_R = 0x002, // Read
|
||||
PTE_W = 0x004, // Write
|
||||
PTE_X = 0x008, // Execute
|
||||
PTE_U = 0x010, // User
|
||||
PTE_G = 0x020, // Global
|
||||
PTE_A = 0x040, // Accessed
|
||||
PTE_D = 0x080, // Dirty
|
||||
PTE_SOFT = 0x300 // Reserved for Software
|
||||
};
|
||||
|
||||
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
|
||||
|
||||
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
|
||||
|
||||
enum {
|
||||
ISA_A = 1,
|
||||
ISA_B = 1 << 1,
|
||||
ISA_C = 1 << 2,
|
||||
ISA_D = 1 << 3,
|
||||
ISA_E = 1 << 4,
|
||||
ISA_F = 1 << 5,
|
||||
ISA_G = 1 << 6,
|
||||
ISA_I = 1 << 8,
|
||||
ISA_M = 1 << 12,
|
||||
ISA_N = 1 << 13,
|
||||
ISA_Q = 1 << 16,
|
||||
ISA_S = 1 << 18,
|
||||
ISA_U = 1 << 20
|
||||
};
|
||||
|
||||
struct vm_info {
|
||||
int levels;
|
||||
int idxbits;
|
||||
int ptesize;
|
||||
uint64_t ptbase;
|
||||
bool is_active() { return levels; }
|
||||
};
|
||||
|
||||
class trap_load_access_fault : public trap_access {
|
||||
public:
|
||||
trap_load_access_fault(uint64_t badaddr)
|
||||
: trap_access(5 << 16, badaddr) {}
|
||||
};
|
||||
class illegal_instruction_fault : public trap_access {
|
||||
public:
|
||||
illegal_instruction_fault(uint64_t badaddr)
|
||||
: trap_access(2 << 16, badaddr) {}
|
||||
};
|
||||
class trap_instruction_page_fault : public trap_access {
|
||||
public:
|
||||
trap_instruction_page_fault(uint64_t badaddr)
|
||||
: trap_access(12 << 16, badaddr) {}
|
||||
};
|
||||
class trap_load_page_fault : public trap_access {
|
||||
public:
|
||||
trap_load_page_fault(uint64_t badaddr)
|
||||
: trap_access(13 << 16, badaddr) {}
|
||||
};
|
||||
class trap_store_page_fault : public trap_access {
|
||||
public:
|
||||
trap_store_page_fault(uint64_t badaddr)
|
||||
: trap_access(15 << 16, badaddr) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
1388
incl/iss/arch/riscv_hart_msu_vp.h
Normal file
1388
incl/iss/arch/riscv_hart_msu_vp.h
Normal file
File diff suppressed because it is too large
Load Diff
1392
incl/iss/arch/riscv_hart_mu_p.h
Normal file
1392
incl/iss/arch/riscv_hart_mu_p.h
Normal file
File diff suppressed because it is too large
Load Diff
277
incl/iss/arch/tgc_c.h
Normal file
277
incl/iss/arch/tgc_c.h
Normal file
@ -0,0 +1,277 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _TGC_C_H_
|
||||
#define _TGC_C_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgc_c;
|
||||
|
||||
template <> struct traits<tgc_c> {
|
||||
|
||||
constexpr static char const* const core_type = "TGC_C";
|
||||
|
||||
static constexpr std::array<const char*, 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"}};
|
||||
|
||||
static constexpr std::array<const char*, 36> reg_aliases{
|
||||
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
|
||||
|
||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
enum reg_e {
|
||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
ICOUNT,
|
||||
CYCLE,
|
||||
INSTRET
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 41> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 41> reg_byte_offsets{
|
||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
|
||||
enum class opcode_e : unsigned short {
|
||||
LUI = 0,
|
||||
AUIPC = 1,
|
||||
JAL = 2,
|
||||
JALR = 3,
|
||||
BEQ = 4,
|
||||
BNE = 5,
|
||||
BLT = 6,
|
||||
BGE = 7,
|
||||
BLTU = 8,
|
||||
BGEU = 9,
|
||||
LB = 10,
|
||||
LH = 11,
|
||||
LW = 12,
|
||||
LBU = 13,
|
||||
LHU = 14,
|
||||
SB = 15,
|
||||
SH = 16,
|
||||
SW = 17,
|
||||
ADDI = 18,
|
||||
SLTI = 19,
|
||||
SLTIU = 20,
|
||||
XORI = 21,
|
||||
ORI = 22,
|
||||
ANDI = 23,
|
||||
SLLI = 24,
|
||||
SRLI = 25,
|
||||
SRAI = 26,
|
||||
ADD = 27,
|
||||
SUB = 28,
|
||||
SLL = 29,
|
||||
SLT = 30,
|
||||
SLTU = 31,
|
||||
XOR = 32,
|
||||
SRL = 33,
|
||||
SRA = 34,
|
||||
OR = 35,
|
||||
AND = 36,
|
||||
FENCE = 37,
|
||||
ECALL = 38,
|
||||
EBREAK = 39,
|
||||
URET = 40,
|
||||
SRET = 41,
|
||||
MRET = 42,
|
||||
WFI = 43,
|
||||
DRET = 44,
|
||||
CSRRW = 45,
|
||||
CSRRS = 46,
|
||||
CSRRC = 47,
|
||||
CSRRWI = 48,
|
||||
CSRRSI = 49,
|
||||
CSRRCI = 50,
|
||||
FENCE_I = 51,
|
||||
MUL = 52,
|
||||
MULH = 53,
|
||||
MULHSU = 54,
|
||||
MULHU = 55,
|
||||
DIV = 56,
|
||||
DIVU = 57,
|
||||
REM = 58,
|
||||
REMU = 59,
|
||||
CADDI4SPN = 60,
|
||||
CLW = 61,
|
||||
CSW = 62,
|
||||
CADDI = 63,
|
||||
CNOP = 64,
|
||||
CJAL = 65,
|
||||
CLI = 66,
|
||||
CLUI = 67,
|
||||
CADDI16SP = 68,
|
||||
__reserved_clui = 69,
|
||||
CSRLI = 70,
|
||||
CSRAI = 71,
|
||||
CANDI = 72,
|
||||
CSUB = 73,
|
||||
CXOR = 74,
|
||||
COR = 75,
|
||||
CAND = 76,
|
||||
CJ = 77,
|
||||
CBEQZ = 78,
|
||||
CBNEZ = 79,
|
||||
CSLLI = 80,
|
||||
CLWSP = 81,
|
||||
CMV = 82,
|
||||
CJR = 83,
|
||||
__reserved_cmv = 84,
|
||||
CADD = 85,
|
||||
CJALR = 86,
|
||||
CEBREAK = 87,
|
||||
CSWSP = 88,
|
||||
DII = 89,
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
|
||||
struct tgc_c: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgc_c>::reg_t;
|
||||
using addr_t = typename traits<tgc_c>::addr_t;
|
||||
|
||||
tgc_c();
|
||||
~tgc_c();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
|
||||
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||
if (addr.space != traits<tgc_c>::MEM || addr.type == iss::address_type::PHYSICAL ||
|
||||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc_c>::addr_mask);
|
||||
} else
|
||||
return virt2phys(addr);
|
||||
}
|
||||
|
||||
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
struct TGC_C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint8_t PRIV = 0;
|
||||
uint32_t DPC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGC_C_H_ */
|
@ -1,252 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef _TGF_B_H_
|
||||
#define _TGF_B_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgf_b;
|
||||
|
||||
template <> struct traits<tgf_b> {
|
||||
|
||||
constexpr static char const* const core_type = "TGF_B";
|
||||
|
||||
static constexpr std::array<const char*, 33> reg_names{
|
||||
{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}};
|
||||
|
||||
static constexpr std::array<const char*, 33> reg_aliases{
|
||||
{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}};
|
||||
|
||||
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000000000000000100000000, PGSIZE=0x1000, PGMASK=0xfff};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
enum reg_e {
|
||||
X0,
|
||||
X1,
|
||||
X2,
|
||||
X3,
|
||||
X4,
|
||||
X5,
|
||||
X6,
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X11,
|
||||
X12,
|
||||
X13,
|
||||
X14,
|
||||
X15,
|
||||
X16,
|
||||
X17,
|
||||
X18,
|
||||
X19,
|
||||
X20,
|
||||
X21,
|
||||
X22,
|
||||
X23,
|
||||
X24,
|
||||
X25,
|
||||
X26,
|
||||
X27,
|
||||
X28,
|
||||
X29,
|
||||
X30,
|
||||
X31,
|
||||
PC,
|
||||
NUM_REGS,
|
||||
NEXT_PC=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT,
|
||||
ZERO = X0,
|
||||
RA = X1,
|
||||
SP = X2,
|
||||
GP = X3,
|
||||
TP = X4,
|
||||
T0 = X5,
|
||||
T1 = X6,
|
||||
T2 = X7,
|
||||
S0 = X8,
|
||||
S1 = X9,
|
||||
A0 = X10,
|
||||
A1 = X11,
|
||||
A2 = X12,
|
||||
A3 = X13,
|
||||
A4 = X14,
|
||||
A5 = X15,
|
||||
A6 = X16,
|
||||
A7 = X17,
|
||||
S2 = X18,
|
||||
S3 = X19,
|
||||
S4 = X20,
|
||||
S5 = X21,
|
||||
S6 = X22,
|
||||
S7 = X23,
|
||||
S8 = X24,
|
||||
S9 = X25,
|
||||
S10 = X26,
|
||||
S11 = X27,
|
||||
T3 = X28,
|
||||
T4 = X29,
|
||||
T5 = X30,
|
||||
T6 = X31
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 39> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
|
||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
};
|
||||
|
||||
struct tgf_b: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgf_b>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgf_b>::phys_addr_t;
|
||||
using reg_t = typename traits<tgf_b>::reg_t;
|
||||
using addr_t = typename traits<tgf_b>::addr_t;
|
||||
|
||||
tgf_b();
|
||||
~tgf_b();
|
||||
|
||||
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<tgf_b>::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<tgf_b>::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 TGF_B_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGF_B_H_ */
|
@ -1,252 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef _TGF_C_H_
|
||||
#define _TGF_C_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgf_c;
|
||||
|
||||
template <> struct traits<tgf_c> {
|
||||
|
||||
constexpr static char const* const core_type = "TGF_C";
|
||||
|
||||
static constexpr std::array<const char*, 33> reg_names{
|
||||
{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}};
|
||||
|
||||
static constexpr std::array<const char*, 33> reg_aliases{
|
||||
{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}};
|
||||
|
||||
enum constants {XLEN=32, PCLEN=32, MUL_LEN=64, MISA_VAL=0b1000000000000000001000100000100, PGSIZE=0x1000, PGMASK=0xfff};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
enum reg_e {
|
||||
X0,
|
||||
X1,
|
||||
X2,
|
||||
X3,
|
||||
X4,
|
||||
X5,
|
||||
X6,
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X11,
|
||||
X12,
|
||||
X13,
|
||||
X14,
|
||||
X15,
|
||||
X16,
|
||||
X17,
|
||||
X18,
|
||||
X19,
|
||||
X20,
|
||||
X21,
|
||||
X22,
|
||||
X23,
|
||||
X24,
|
||||
X25,
|
||||
X26,
|
||||
X27,
|
||||
X28,
|
||||
X29,
|
||||
X30,
|
||||
X31,
|
||||
PC,
|
||||
NUM_REGS,
|
||||
NEXT_PC=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT,
|
||||
ZERO = X0,
|
||||
RA = X1,
|
||||
SP = X2,
|
||||
GP = X3,
|
||||
TP = X4,
|
||||
T0 = X5,
|
||||
T1 = X6,
|
||||
T2 = X7,
|
||||
S0 = X8,
|
||||
S1 = X9,
|
||||
A0 = X10,
|
||||
A1 = X11,
|
||||
A2 = X12,
|
||||
A3 = X13,
|
||||
A4 = X14,
|
||||
A5 = X15,
|
||||
A6 = X16,
|
||||
A7 = X17,
|
||||
S2 = X18,
|
||||
S3 = X19,
|
||||
S4 = X20,
|
||||
S5 = X21,
|
||||
S6 = X22,
|
||||
S7 = X23,
|
||||
S8 = X24,
|
||||
S9 = X25,
|
||||
S10 = X26,
|
||||
S11 = X27,
|
||||
T3 = X28,
|
||||
T4 = X29,
|
||||
T5 = X30,
|
||||
T6 = X31
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 39> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
|
||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
};
|
||||
|
||||
struct tgf_c: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgf_c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgf_c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgf_c>::reg_t;
|
||||
using addr_t = typename traits<tgf_c>::addr_t;
|
||||
|
||||
tgf_c();
|
||||
~tgf_c();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
/// deprecated
|
||||
void get_reg(short idx, std::vector<uint8_t>& value) override {}
|
||||
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
|
||||
/// deprecated
|
||||
bool get_flag(int flag) override {return false;}
|
||||
void set_flag(int, bool value) override {};
|
||||
/// deprecated
|
||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
|
||||
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||
if (addr.space != traits<tgf_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<tgf_c>::addr_mask);
|
||||
} else
|
||||
return virt2phys(addr);
|
||||
}
|
||||
|
||||
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
struct TGF_C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGF_C_H_ */
|
@ -183,7 +183,8 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
||||
data.clear();
|
||||
avail.clear();
|
||||
const uint8_t *reg_base = core->get_regs_base_ptr();
|
||||
for (size_t reg_no = 0; reg_no < arch::traits<ARCH>::NUM_REGS; ++reg_no) {
|
||||
auto start_reg=arch::traits<ARCH>::X0;
|
||||
for (size_t reg_no = start_reg; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
for (size_t j = 0; j < reg_width; ++j) {
|
||||
@ -210,11 +211,11 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(const std::vector<uint8_t> &data) {
|
||||
auto reg_count = arch::traits<ARCH>::NUM_REGS;
|
||||
auto start_reg=arch::traits<ARCH>::X0;
|
||||
auto *reg_base = core->get_regs_base_ptr();
|
||||
auto iter = data.data();
|
||||
for (size_t reg_no = 0; reg_no < reg_count; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
|
||||
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
iter += 4;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,41 +29,34 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/tgf_c.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
using namespace iss::arch;
|
||||
#ifndef _ISS_FACTORY_H_
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_c>::reg_names;
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::tgf_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgf_c>::reg_byte_offsets;
|
||||
#include <iss/iss.h>
|
||||
|
||||
tgf_c::tgf_c() {
|
||||
reg.icount = 0;
|
||||
namespace iss {
|
||||
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
template<typename PLAT>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
|
||||
using core_type = typename PLAT::core;
|
||||
core_type* lcpu = new PLAT();
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "tcc")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
tgf_c::~tgf_c() = default;
|
||||
|
||||
void tgf_c::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<tgf_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_c>::reg_t),0));
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgf_c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgf_c::phys_addr_t tgf_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
}
|
||||
|
||||
#endif /* _ISS_FACTORY_H_ */
|
@ -76,7 +76,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info) override;
|
||||
void callback(instr_info_t instr_info, exec_info const&) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *arch_instr;
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info) override;
|
||||
void callback(instr_info_t, exec_info const&) override;
|
||||
|
||||
private:
|
||||
Json::Value root;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017-2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -30,34 +30,27 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _SYSC_SIFIVE_FE310_H_
|
||||
#define _SYSC_SIFIVE_FE310_H_
|
||||
#ifndef _SYSC_CORE_COMPLEX_H_
|
||||
#define _SYSC_CORE_COMPLEX_H_
|
||||
|
||||
#include "scc/initiator_mixin.h"
|
||||
#include "scc/traceable.h"
|
||||
#include "scc/utilities.h"
|
||||
#include "scv4tlm/tlm_rec_initiator_socket.h"
|
||||
#include <tlm/scc/initiator_mixin.h>
|
||||
#include <scc/traceable.h>
|
||||
#include <scc/tick2time.h>
|
||||
#include <scc/utilities.h>
|
||||
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
|
||||
#ifdef CWR_SYSTEMC
|
||||
#include <scmlinc/scml_property.h>
|
||||
#else
|
||||
#include <cci_configuration>
|
||||
#endif
|
||||
#include <tlm>
|
||||
#include <tlm_core/tlm_1/tlm_req_rsp/tlm_1_interfaces/tlm_core_ifs.h>
|
||||
#include <tlm_utils/tlm_quantumkeeper.h>
|
||||
#include <util/range_lut.h>
|
||||
|
||||
class scv_tr_db;
|
||||
class scv_tr_stream;
|
||||
struct _scv_tr_generator_default_data;
|
||||
template <class T_begin, class T_end> class scv_tr_generator;
|
||||
#include <memory>
|
||||
|
||||
namespace iss {
|
||||
class vm_if;
|
||||
namespace arch {
|
||||
template <typename BASE> class riscv_hart_m_p;
|
||||
class vm_plugin;
|
||||
}
|
||||
namespace debugger {
|
||||
class target_adapter_if;
|
||||
}
|
||||
} // namespace iss
|
||||
|
||||
namespace sysc {
|
||||
|
||||
class tlm_dmi_ext : public tlm::tlm_dmi {
|
||||
@ -70,14 +63,13 @@ public:
|
||||
bool operator!=(const tlm_dmi_ext &o) const { return !operator==(o); }
|
||||
};
|
||||
|
||||
namespace SiFive {
|
||||
namespace tgfs {
|
||||
class core_wrapper;
|
||||
struct core_trace;
|
||||
|
||||
class core_complex : public sc_core::sc_module, public scc::traceable {
|
||||
public:
|
||||
scc::initiator_mixin<scv4tlm::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
||||
|
||||
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
||||
tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
||||
|
||||
sc_core::sc_in<bool> rst_i{"rst_i"};
|
||||
|
||||
@ -89,6 +81,9 @@ public:
|
||||
|
||||
sc_core::sc_vector<sc_core::sc_in<bool>> local_irq_i{"local_irq_i", 16};
|
||||
|
||||
#ifndef CWR_SYSTEMC
|
||||
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
||||
|
||||
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o;
|
||||
|
||||
cci::cci_param<std::string> elf_file{"elf_file", ""};
|
||||
@ -97,7 +92,9 @@ public:
|
||||
|
||||
cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
|
||||
|
||||
cci::cci_param<std::string> backend{"backend", "tcc"};
|
||||
cci::cci_param<std::string> core_type{"core_type", "tgc_c"};
|
||||
|
||||
cci::cci_param<std::string> backend{"backend", "interp"};
|
||||
|
||||
cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0};
|
||||
|
||||
@ -105,7 +102,51 @@ public:
|
||||
|
||||
cci::cci_param<uint32_t> mhartid{"mhartid", 0};
|
||||
|
||||
core_complex(sc_core::sc_module_name name);
|
||||
cci::cci_param<std::string> plugins{"plugins", ""};
|
||||
|
||||
core_complex(sc_core::sc_module_name const& name);
|
||||
|
||||
#else
|
||||
sc_core::sc_in<bool> clk_i{"clk_i"};
|
||||
|
||||
sc_core::sc_in<uint64_t> mtime_i{"mtime_i"};
|
||||
|
||||
scml_property<std::string> elf_file{"elf_file", ""};
|
||||
|
||||
scml_property<bool> enable_disass{"enable_disass", false};
|
||||
|
||||
scml_property<unsigned long long> reset_address{"reset_address", 0ULL};
|
||||
|
||||
scml_property<std::string> core_type{"core_type", "tgc_c"};
|
||||
|
||||
scml_property<std::string> backend{"backend", "interp"};
|
||||
|
||||
scml_property<unsigned> gdb_server_port{"gdb_server_port", 0};
|
||||
|
||||
scml_property<bool> dump_ir{"dump_ir", false};
|
||||
|
||||
scml_property<uint32_t> mhartid{"mhartid", 0};
|
||||
|
||||
scml_property<std::string> plugins{"plugins", ""};
|
||||
|
||||
core_complex(sc_core::sc_module_name const& name)
|
||||
: sc_module(name)
|
||||
, local_irq_i{"local_irq_i", 16}
|
||||
, elf_file{"elf_file", ""}
|
||||
, enable_disass{"enable_disass", false}
|
||||
, reset_address{"reset_address", 0ULL}
|
||||
, core_type{"core_type", "tgc_c"}
|
||||
, backend{"backend", "interp"}
|
||||
, gdb_server_port{"gdb_server_port", 0}
|
||||
, dump_ir{"dump_ir", false}
|
||||
, mhartid{"mhartid", 0}
|
||||
, read_lut(tlm_dmi_ext())
|
||||
, write_lut(tlm_dmi_ext())
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
~core_complex();
|
||||
|
||||
@ -129,13 +170,14 @@ public:
|
||||
|
||||
void trace(sc_core::sc_trace_file *trf) const override;
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr);
|
||||
bool disass_output(uint64_t pc, const std::string instr);
|
||||
|
||||
void set_clock_period(sc_core::sc_time period);
|
||||
protected:
|
||||
void before_end_of_elaboration() override;
|
||||
void start_of_simulation() override;
|
||||
void forward();
|
||||
void run();
|
||||
void clk_cb();
|
||||
void rst_cb();
|
||||
void sw_irq_cb();
|
||||
void timer_irq_cb();
|
||||
@ -144,23 +186,16 @@ protected:
|
||||
util::range_lut<tlm_dmi_ext> read_lut, write_lut;
|
||||
tlm_utils::tlm_quantumkeeper quantum_keeper;
|
||||
std::vector<uint8_t> write_buf;
|
||||
std::unique_ptr<core_wrapper> cpu;
|
||||
std::unique_ptr<iss::vm_if> vm;
|
||||
sc_core::sc_time curr_clk;
|
||||
iss::debugger::target_adapter_if *tgt_adapter;
|
||||
#ifdef WITH_SCV
|
||||
//! transaction recording database
|
||||
scv_tr_db *m_db;
|
||||
//! blocking transaction recording stream handle
|
||||
scv_tr_stream *stream_handle;
|
||||
//! transaction generator handle for blocking transactions
|
||||
scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data> *instr_tr_handle;
|
||||
scv_tr_generator<uint64_t, _scv_tr_generator_default_data> *fetch_tr_handle;
|
||||
scv_tr_handle tr_handle;
|
||||
#endif
|
||||
};
|
||||
core_wrapper* cpu{nullptr};
|
||||
sc_core::sc_signal<sc_core::sc_time> curr_clk;
|
||||
core_trace* trc{nullptr};
|
||||
std::unique_ptr<scc::tick2time> t2t;
|
||||
private:
|
||||
void init();
|
||||
std::vector<iss::vm_plugin *> plugin_list;
|
||||
|
||||
};
|
||||
} /* namespace SiFive */
|
||||
} /* namespace sysc */
|
||||
|
||||
#endif /* _SYSC_SIFIVE_FE310_H_ */
|
||||
#endif /* _SYSC_CORE_COMPLEX_H_ */
|
||||
|
@ -49,7 +49,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC__
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#define SOFTFLOAT_INTRINSIC_INT128 1
|
||||
#endif
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
1
src/iss/.gitignore
vendored
Normal file
1
src/iss/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/tgc_*.cpp
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,41 +29,43 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/tgf_b.h>
|
||||
#include <iss/arch/tgc_c.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_b>::reg_names;
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_b>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::tgf_b>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgf_b>::reg_byte_offsets;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
|
||||
tgf_b::tgf_b() {
|
||||
tgc_c::tgc_c() {
|
||||
reg.icount = 0;
|
||||
}
|
||||
|
||||
tgf_b::~tgf_b() = default;
|
||||
tgc_c::~tgc_c() = default;
|
||||
|
||||
void tgf_b::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<tgf_b>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_b>::reg_t),0));
|
||||
void tgc_c::reset(uint64_t address) {
|
||||
auto base_ptr = reinterpret_cast<traits<tgc_c>::reg_t*>(get_regs_base_ptr());
|
||||
for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i)
|
||||
*(base_ptr+i)=0;
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgf_b::get_regs_base_ptr() {
|
||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgf_b::phys_addr_t tgf_b::virt2phys(const iss::addr_t &pc) {
|
||||
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
}
|
||||
|
95
src/main.cpp
95
src/main.cpp
@ -31,39 +31,42 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/factory.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/tgf_b.h>
|
||||
#include <iss/arch/tgf_c.h>
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_mac.h"
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_helper.h>
|
||||
#endif
|
||||
#include <iss/log_categories.h>
|
||||
#include <iss/plugin/cycle_estimate.h>
|
||||
#include <iss/plugin/instruction_count.h>
|
||||
#include <iss/plugin/loader.h>
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
template<typename CORE>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
|
||||
CORE* lcpu = new iss::arch::riscv_hart_m_p<CORE>();
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
if(backend == "tcc")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
@ -83,8 +86,8 @@ int main(int argc, char *argv[]) {
|
||||
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||
("mem,m", po::value<std::string>(), "the memory input file")
|
||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||
("backend", po::value<std::string>()->default_value("tcc"), "the memory input file")
|
||||
("isa", po::value<std::string>()->default_value("tgf_c"), "isa to use for simulation");
|
||||
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
||||
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
|
||||
// clang-format on
|
||||
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
try {
|
||||
@ -126,17 +129,33 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
bool dump = clim.count("dump-ir");
|
||||
// instantiate the simulator
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if (isa_opt == "tgf_b") {
|
||||
if (isa_opt == "tgc_c") {
|
||||
std::tie(cpu, vm) =
|
||||
create_cpu<iss::arch::tgf_b>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else if (isa_opt == "tgf_c") {
|
||||
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#ifdef CORE_TGC_B
|
||||
if (isa_opt == "tgc_b") {
|
||||
std::tie(cpu, vm) =
|
||||
create_cpu<iss::arch::tgf_c>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else {
|
||||
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
|
||||
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
if (isa_opt == "tgc_d") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
if (isa_opt == "tgc_d_xrb_mac") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
|
||||
return 127;
|
||||
}
|
||||
if (clim.count("plugin")) {
|
||||
@ -157,8 +176,16 @@ int main(int argc, char *argv[]) {
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else {
|
||||
LOG(ERROR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
if(plugin){
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,7 +201,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("mem"))
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::tgf_b>::MEM);
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>());
|
||||
if (clim.count("elf"))
|
||||
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
|
||||
auto start_addr = vm->get_arch()->load_file(input);
|
||||
@ -192,7 +219,7 @@ int main(int argc, char *argv[]) {
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
} catch (std::exception &e) {
|
||||
LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||
<< std::endl;
|
||||
res = 2;
|
||||
}
|
||||
|
@ -1,821 +0,0 @@
|
||||
//===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// GCOV implements the interface to read and write coverage files that use
|
||||
// 'gcov' format.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GCOV.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <system_error>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVFile implementation.
|
||||
|
||||
/// readGCNO - Read GCNO buffer.
|
||||
bool GCOVFile::readGCNO(GCOVBuffer &Buffer) {
|
||||
if (!Buffer.readGCNOFormat())
|
||||
return false;
|
||||
if (!Buffer.readGCOVVersion(Version))
|
||||
return false;
|
||||
|
||||
if (!Buffer.readInt(Checksum))
|
||||
return false;
|
||||
while (true) {
|
||||
if (!Buffer.readFunctionTag())
|
||||
break;
|
||||
auto GFun = make_unique<GCOVFunction>(*this);
|
||||
if (!GFun->readGCNO(Buffer, Version))
|
||||
return false;
|
||||
Functions.push_back(std::move(GFun));
|
||||
}
|
||||
|
||||
GCNOInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
|
||||
/// called after readGCNO().
|
||||
bool GCOVFile::readGCDA(GCOVBuffer &Buffer) {
|
||||
assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
|
||||
if (!Buffer.readGCDAFormat())
|
||||
return false;
|
||||
GCOV::GCOVVersion GCDAVersion;
|
||||
if (!Buffer.readGCOVVersion(GCDAVersion))
|
||||
return false;
|
||||
if (Version != GCDAVersion) {
|
||||
errs() << "GCOV versions do not match.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GCDAChecksum;
|
||||
if (!Buffer.readInt(GCDAChecksum))
|
||||
return false;
|
||||
if (Checksum != GCDAChecksum) {
|
||||
errs() << "File checksums do not match: " << Checksum
|
||||
<< " != " << GCDAChecksum << ".\n";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0, e = Functions.size(); i < e; ++i) {
|
||||
if (!Buffer.readFunctionTag()) {
|
||||
errs() << "Unexpected number of functions.\n";
|
||||
return false;
|
||||
}
|
||||
if (!Functions[i]->readGCDA(Buffer, Version))
|
||||
return false;
|
||||
}
|
||||
if (Buffer.readObjectTag()) {
|
||||
uint32_t Length;
|
||||
uint32_t Dummy;
|
||||
if (!Buffer.readInt(Length))
|
||||
return false;
|
||||
if (!Buffer.readInt(Dummy))
|
||||
return false; // checksum
|
||||
if (!Buffer.readInt(Dummy))
|
||||
return false; // num
|
||||
if (!Buffer.readInt(RunCount))
|
||||
return false;
|
||||
Buffer.advanceCursor(Length - 3);
|
||||
}
|
||||
while (Buffer.readProgramTag()) {
|
||||
uint32_t Length;
|
||||
if (!Buffer.readInt(Length))
|
||||
return false;
|
||||
Buffer.advanceCursor(Length);
|
||||
++ProgramCount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GCOVFile::print(raw_ostream &OS) const {
|
||||
for (const auto &FPtr : Functions)
|
||||
FPtr->print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
/// dump - Dump GCOVFile content to dbgs() for debugging purposes.
|
||||
LLVM_DUMP_METHOD void GCOVFile::dump() const {
|
||||
print(dbgs());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// collectLineCounts - Collect line counts. This must be used after
|
||||
/// reading .gcno and .gcda files.
|
||||
void GCOVFile::collectLineCounts(FileInfo &FI) {
|
||||
for (const auto &FPtr : Functions)
|
||||
FPtr->collectLineCounts(FI);
|
||||
FI.setRunCount(RunCount);
|
||||
FI.setProgramCount(ProgramCount);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVFunction implementation.
|
||||
|
||||
/// readGCNO - Read a function from the GCNO buffer. Return false if an error
|
||||
/// occurs.
|
||||
bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
uint32_t Dummy;
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false; // Function header length
|
||||
if (!Buff.readInt(Ident))
|
||||
return false;
|
||||
if (!Buff.readInt(Checksum))
|
||||
return false;
|
||||
if (Version != GCOV::V402) {
|
||||
uint32_t CfgChecksum;
|
||||
if (!Buff.readInt(CfgChecksum))
|
||||
return false;
|
||||
if (Parent.getChecksum() != CfgChecksum) {
|
||||
errs() << "File checksums do not match: " << Parent.getChecksum()
|
||||
<< " != " << CfgChecksum << " in (" << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!Buff.readString(Name))
|
||||
return false;
|
||||
if (!Buff.readString(Filename))
|
||||
return false;
|
||||
if (!Buff.readInt(LineNumber))
|
||||
return false;
|
||||
|
||||
// read blocks.
|
||||
if (!Buff.readBlockTag()) {
|
||||
errs() << "Block tag not found.\n";
|
||||
return false;
|
||||
}
|
||||
uint32_t BlockCount;
|
||||
if (!Buff.readInt(BlockCount))
|
||||
return false;
|
||||
for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false; // Block flags;
|
||||
Blocks.push_back(make_unique<GCOVBlock>(*this, i));
|
||||
}
|
||||
|
||||
// read edges.
|
||||
while (Buff.readEdgeTag()) {
|
||||
uint32_t EdgeCount;
|
||||
if (!Buff.readInt(EdgeCount))
|
||||
return false;
|
||||
EdgeCount = (EdgeCount - 1) / 2;
|
||||
uint32_t BlockNo;
|
||||
if (!Buff.readInt(BlockNo))
|
||||
return false;
|
||||
if (BlockNo >= BlockCount) {
|
||||
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
|
||||
<< ").\n";
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
|
||||
uint32_t Dst;
|
||||
if (!Buff.readInt(Dst))
|
||||
return false;
|
||||
Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst]));
|
||||
GCOVEdge *Edge = Edges.back().get();
|
||||
Blocks[BlockNo]->addDstEdge(Edge);
|
||||
Blocks[Dst]->addSrcEdge(Edge);
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false; // Edge flag
|
||||
}
|
||||
}
|
||||
|
||||
// read line table.
|
||||
while (Buff.readLineTag()) {
|
||||
uint32_t LineTableLength;
|
||||
// Read the length of this line table.
|
||||
if (!Buff.readInt(LineTableLength))
|
||||
return false;
|
||||
uint32_t EndPos = Buff.getCursor() + LineTableLength * 4;
|
||||
uint32_t BlockNo;
|
||||
// Read the block number this table is associated with.
|
||||
if (!Buff.readInt(BlockNo))
|
||||
return false;
|
||||
if (BlockNo >= BlockCount) {
|
||||
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
|
||||
<< ").\n";
|
||||
return false;
|
||||
}
|
||||
GCOVBlock &Block = *Blocks[BlockNo];
|
||||
// Read the word that pads the beginning of the line table. This may be a
|
||||
// flag of some sort, but seems to always be zero.
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false;
|
||||
|
||||
// Line information starts here and continues up until the last word.
|
||||
if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) {
|
||||
StringRef F;
|
||||
// Read the source file name.
|
||||
if (!Buff.readString(F))
|
||||
return false;
|
||||
if (Filename != F) {
|
||||
errs() << "Multiple sources for a single basic block: " << Filename
|
||||
<< " != " << F << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
// Read lines up to, but not including, the null terminator.
|
||||
while (Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) {
|
||||
uint32_t Line;
|
||||
if (!Buff.readInt(Line))
|
||||
return false;
|
||||
// Line 0 means this instruction was injected by the compiler. Skip it.
|
||||
if (!Line)
|
||||
continue;
|
||||
Block.addLine(Line);
|
||||
}
|
||||
// Read the null terminator.
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false;
|
||||
}
|
||||
// The last word is either a flag or padding, it isn't clear which. Skip
|
||||
// over it.
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCDA - Read a function from the GCDA buffer. Return false if an error
|
||||
/// occurs.
|
||||
bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
uint32_t HeaderLength;
|
||||
if (!Buff.readInt(HeaderLength))
|
||||
return false; // Function header length
|
||||
|
||||
uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t);
|
||||
|
||||
uint32_t GCDAIdent;
|
||||
if (!Buff.readInt(GCDAIdent))
|
||||
return false;
|
||||
if (Ident != GCDAIdent) {
|
||||
errs() << "Function identifiers do not match: " << Ident
|
||||
<< " != " << GCDAIdent << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GCDAChecksum;
|
||||
if (!Buff.readInt(GCDAChecksum))
|
||||
return false;
|
||||
if (Checksum != GCDAChecksum) {
|
||||
errs() << "Function checksums do not match: " << Checksum
|
||||
<< " != " << GCDAChecksum << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t CfgChecksum;
|
||||
if (Version != GCOV::V402) {
|
||||
if (!Buff.readInt(CfgChecksum))
|
||||
return false;
|
||||
if (Parent.getChecksum() != CfgChecksum) {
|
||||
errs() << "File checksums do not match: " << Parent.getChecksum()
|
||||
<< " != " << CfgChecksum << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Buff.getCursor() < EndPos) {
|
||||
StringRef GCDAName;
|
||||
if (!Buff.readString(GCDAName))
|
||||
return false;
|
||||
if (Name != GCDAName) {
|
||||
errs() << "Function names do not match: " << Name << " != " << GCDAName
|
||||
<< ".\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Buff.readArcTag()) {
|
||||
errs() << "Arc tag not found (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t Count;
|
||||
if (!Buff.readInt(Count))
|
||||
return false;
|
||||
Count /= 2;
|
||||
|
||||
// This for loop adds the counts for each block. A second nested loop is
|
||||
// required to combine the edge counts that are contained in the GCDA file.
|
||||
for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
|
||||
// The last block is always reserved for exit block
|
||||
if (BlockNo >= Blocks.size()) {
|
||||
errs() << "Unexpected number of edges (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
if (BlockNo == Blocks.size() - 1)
|
||||
errs() << "(" << Name << ") has arcs from exit block.\n";
|
||||
GCOVBlock &Block = *Blocks[BlockNo];
|
||||
for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End;
|
||||
++EdgeNo) {
|
||||
if (Count == 0) {
|
||||
errs() << "Unexpected number of edges (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
uint64_t ArcCount;
|
||||
if (!Buff.readInt64(ArcCount))
|
||||
return false;
|
||||
Block.addCount(EdgeNo, ArcCount);
|
||||
--Count;
|
||||
}
|
||||
Block.sortDstEdges();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// getEntryCount - Get the number of times the function was called by
|
||||
/// retrieving the entry block's count.
|
||||
uint64_t GCOVFunction::getEntryCount() const {
|
||||
return Blocks.front()->getCount();
|
||||
}
|
||||
|
||||
/// getExitCount - Get the number of times the function returned by retrieving
|
||||
/// the exit block's count.
|
||||
uint64_t GCOVFunction::getExitCount() const {
|
||||
return Blocks.back()->getCount();
|
||||
}
|
||||
|
||||
void GCOVFunction::print(raw_ostream &OS) const {
|
||||
OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":"
|
||||
<< LineNumber << "\n";
|
||||
for (const auto &Block : Blocks)
|
||||
Block->print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
/// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
|
||||
LLVM_DUMP_METHOD void GCOVFunction::dump() const {
|
||||
print(dbgs());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// collectLineCounts - Collect line counts. This must be used after
|
||||
/// reading .gcno and .gcda files.
|
||||
void GCOVFunction::collectLineCounts(FileInfo &FI) {
|
||||
// If the line number is zero, this is a function that doesn't actually appear
|
||||
// in the source file, so there isn't anything we can do with it.
|
||||
if (LineNumber == 0)
|
||||
return;
|
||||
|
||||
for (const auto &Block : Blocks)
|
||||
Block->collectLineCounts(FI);
|
||||
FI.addFunctionLine(Filename, LineNumber, this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVBlock implementation.
|
||||
|
||||
/// ~GCOVBlock - Delete GCOVBlock and its content.
|
||||
GCOVBlock::~GCOVBlock() {
|
||||
SrcEdges.clear();
|
||||
DstEdges.clear();
|
||||
Lines.clear();
|
||||
}
|
||||
|
||||
/// addCount - Add to block counter while storing the edge count. If the
|
||||
/// destination has no outgoing edges, also update that block's count too.
|
||||
void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
|
||||
assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid
|
||||
DstEdges[DstEdgeNo]->Count = N;
|
||||
Counter += N;
|
||||
if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
|
||||
DstEdges[DstEdgeNo]->Dst.Counter += N;
|
||||
}
|
||||
|
||||
/// sortDstEdges - Sort destination edges by block number, nop if already
|
||||
/// sorted. This is required for printing branch info in the correct order.
|
||||
void GCOVBlock::sortDstEdges() {
|
||||
if (!DstEdgesAreSorted) {
|
||||
SortDstEdgesFunctor SortEdges;
|
||||
std::stable_sort(DstEdges.begin(), DstEdges.end(), SortEdges);
|
||||
}
|
||||
}
|
||||
|
||||
/// collectLineCounts - Collect line counts. This must be used after
|
||||
/// reading .gcno and .gcda files.
|
||||
void GCOVBlock::collectLineCounts(FileInfo &FI) {
|
||||
for (uint32_t N : Lines)
|
||||
FI.addBlockLine(Parent.getFilename(), N, this);
|
||||
}
|
||||
|
||||
void GCOVBlock::print(raw_ostream &OS) const {
|
||||
OS << "Block : " << Number << " Counter : " << Counter << "\n";
|
||||
if (!SrcEdges.empty()) {
|
||||
OS << "\tSource Edges : ";
|
||||
for (const GCOVEdge *Edge : SrcEdges)
|
||||
OS << Edge->Src.Number << " (" << Edge->Count << "), ";
|
||||
OS << "\n";
|
||||
}
|
||||
if (!DstEdges.empty()) {
|
||||
OS << "\tDestination Edges : ";
|
||||
for (const GCOVEdge *Edge : DstEdges)
|
||||
OS << Edge->Dst.Number << " (" << Edge->Count << "), ";
|
||||
OS << "\n";
|
||||
}
|
||||
if (!Lines.empty()) {
|
||||
OS << "\tLines : ";
|
||||
for (uint32_t N : Lines)
|
||||
OS << (N) << ",";
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
|
||||
LLVM_DUMP_METHOD void GCOVBlock::dump() const {
|
||||
print(dbgs());
|
||||
}
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FileInfo implementation.
|
||||
|
||||
// Safe integer division, returns 0 if numerator is 0.
|
||||
static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) {
|
||||
if (!Numerator)
|
||||
return 0;
|
||||
return Numerator / Divisor;
|
||||
}
|
||||
|
||||
// This custom division function mimics gcov's branch ouputs:
|
||||
// - Round to closest whole number
|
||||
// - Only output 0% or 100% if it's exactly that value
|
||||
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
|
||||
if (!Numerator)
|
||||
return 0;
|
||||
if (Numerator == Divisor)
|
||||
return 100;
|
||||
|
||||
uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
|
||||
if (Res == 0)
|
||||
return 1;
|
||||
if (Res == 100)
|
||||
return 99;
|
||||
return Res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct formatBranchInfo {
|
||||
formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
|
||||
: Options(Options), Count(Count), Total(Total) {}
|
||||
|
||||
void print(raw_ostream &OS) const {
|
||||
if (!Total)
|
||||
OS << "never executed";
|
||||
else if (Options.BranchCount)
|
||||
OS << "taken " << Count;
|
||||
else
|
||||
OS << "taken " << branchDiv(Count, Total) << "%";
|
||||
}
|
||||
|
||||
const GCOV::Options &Options;
|
||||
uint64_t Count;
|
||||
uint64_t Total;
|
||||
};
|
||||
|
||||
static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
|
||||
FBI.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
class LineConsumer {
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
StringRef Remaining;
|
||||
|
||||
public:
|
||||
LineConsumer(StringRef Filename) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(Filename);
|
||||
if (std::error_code EC = BufferOrErr.getError()) {
|
||||
errs() << Filename << ": " << EC.message() << "\n";
|
||||
Remaining = "";
|
||||
} else {
|
||||
Buffer = std::move(BufferOrErr.get());
|
||||
Remaining = Buffer->getBuffer();
|
||||
}
|
||||
}
|
||||
bool empty() { return Remaining.empty(); }
|
||||
void printNext(raw_ostream &OS, uint32_t LineNum) {
|
||||
StringRef Line;
|
||||
if (empty())
|
||||
Line = "/*EOF*/";
|
||||
else
|
||||
std::tie(Line, Remaining) = Remaining.split("\n");
|
||||
OS << format("%5u:", LineNum) << Line << "\n";
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// Convert a path to a gcov filename. If PreservePaths is true, this
|
||||
/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
|
||||
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
|
||||
if (!PreservePaths)
|
||||
return sys::path::filename(Filename).str();
|
||||
|
||||
// This behaviour is defined by gcov in terms of text replacements, so it's
|
||||
// not likely to do anything useful on filesystems with different textual
|
||||
// conventions.
|
||||
llvm::SmallString<256> Result("");
|
||||
StringRef::iterator I, S, E;
|
||||
for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
|
||||
if (*I != '/')
|
||||
continue;
|
||||
|
||||
if (I - S == 1 && *S == '.') {
|
||||
// ".", the current directory, is skipped.
|
||||
} else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
|
||||
// "..", the parent directory, is replaced with "^".
|
||||
Result.append("^#");
|
||||
} else {
|
||||
if (S < I)
|
||||
// Leave other components intact,
|
||||
Result.append(S, I);
|
||||
// And separate with "#".
|
||||
Result.push_back('#');
|
||||
}
|
||||
S = I + 1;
|
||||
}
|
||||
|
||||
if (S < I)
|
||||
Result.append(S, I);
|
||||
return Result.str();
|
||||
}
|
||||
|
||||
std::string FileInfo::getCoveragePath(StringRef Filename,
|
||||
StringRef MainFilename) {
|
||||
if (Options.NoOutput)
|
||||
// This is probably a bug in gcov, but when -n is specified, paths aren't
|
||||
// mangled at all, and the -l and -p options are ignored. Here, we do the
|
||||
// same.
|
||||
return Filename;
|
||||
|
||||
std::string CoveragePath;
|
||||
if (Options.LongFileNames && !Filename.equals(MainFilename))
|
||||
CoveragePath =
|
||||
mangleCoveragePath(MainFilename, Options.PreservePaths) + "##";
|
||||
CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths) + ".gcov";
|
||||
return CoveragePath;
|
||||
}
|
||||
|
||||
std::unique_ptr<raw_ostream>
|
||||
FileInfo::openCoveragePath(StringRef CoveragePath) {
|
||||
if (Options.NoOutput)
|
||||
return llvm::make_unique<raw_null_ostream>();
|
||||
|
||||
std::error_code EC;
|
||||
auto OS = llvm::make_unique<raw_fd_ostream>(CoveragePath, EC,
|
||||
sys::fs::F_Text);
|
||||
if (EC) {
|
||||
errs() << EC.message() << "\n";
|
||||
return llvm::make_unique<raw_null_ostream>();
|
||||
}
|
||||
return std::move(OS);
|
||||
}
|
||||
|
||||
/// print - Print source files with collected line count information.
|
||||
void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
StringRef GCNOFile, StringRef GCDAFile) {
|
||||
SmallVector<StringRef, 4> Filenames;
|
||||
for (const auto &LI : LineInfo)
|
||||
Filenames.push_back(LI.first());
|
||||
std::sort(Filenames.begin(), Filenames.end());
|
||||
|
||||
for (StringRef Filename : Filenames) {
|
||||
auto AllLines = LineConsumer(Filename);
|
||||
|
||||
std::string CoveragePath = getCoveragePath(Filename, MainFilename);
|
||||
std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath);
|
||||
raw_ostream &CovOS = *CovStream;
|
||||
|
||||
CovOS << " -: 0:Source:" << Filename << "\n";
|
||||
CovOS << " -: 0:Graph:" << GCNOFile << "\n";
|
||||
CovOS << " -: 0:Data:" << GCDAFile << "\n";
|
||||
CovOS << " -: 0:Runs:" << RunCount << "\n";
|
||||
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
|
||||
|
||||
const LineData &Line = LineInfo[Filename];
|
||||
GCOVCoverage FileCoverage(Filename);
|
||||
for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty();
|
||||
++LineIndex) {
|
||||
if (Options.BranchInfo) {
|
||||
FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex);
|
||||
if (FuncsIt != Line.Functions.end())
|
||||
printFunctionSummary(CovOS, FuncsIt->second);
|
||||
}
|
||||
|
||||
BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex);
|
||||
if (BlocksIt == Line.Blocks.end()) {
|
||||
// No basic blocks are on this line. Not an executable line of code.
|
||||
CovOS << " -:";
|
||||
AllLines.printNext(CovOS, LineIndex + 1);
|
||||
} else {
|
||||
const BlockVector &Blocks = BlocksIt->second;
|
||||
|
||||
// Add up the block counts to form line counts.
|
||||
DenseMap<const GCOVFunction *, bool> LineExecs;
|
||||
uint64_t LineCount = 0;
|
||||
for (const GCOVBlock *Block : Blocks) {
|
||||
if (Options.AllBlocks) {
|
||||
// Only take the highest block count for that line.
|
||||
uint64_t BlockCount = Block->getCount();
|
||||
LineCount = LineCount > BlockCount ? LineCount : BlockCount;
|
||||
} else {
|
||||
// Sum up all of the block counts.
|
||||
LineCount += Block->getCount();
|
||||
}
|
||||
|
||||
if (Options.FuncCoverage) {
|
||||
// This is a slightly convoluted way to most accurately gather line
|
||||
// statistics for functions. Basically what is happening is that we
|
||||
// don't want to count a single line with multiple blocks more than
|
||||
// once. However, we also don't simply want to give the total line
|
||||
// count to every function that starts on the line. Thus, what is
|
||||
// happening here are two things:
|
||||
// 1) Ensure that the number of logical lines is only incremented
|
||||
// once per function.
|
||||
// 2) If there are multiple blocks on the same line, ensure that the
|
||||
// number of lines executed is incremented as long as at least
|
||||
// one of the blocks are executed.
|
||||
const GCOVFunction *Function = &Block->getParent();
|
||||
if (FuncCoverages.find(Function) == FuncCoverages.end()) {
|
||||
std::pair<const GCOVFunction *, GCOVCoverage> KeyValue(
|
||||
Function, GCOVCoverage(Function->getName()));
|
||||
FuncCoverages.insert(KeyValue);
|
||||
}
|
||||
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
|
||||
|
||||
if (LineExecs.find(Function) == LineExecs.end()) {
|
||||
if (Block->getCount()) {
|
||||
++FuncCoverage.LinesExec;
|
||||
LineExecs[Function] = true;
|
||||
} else {
|
||||
LineExecs[Function] = false;
|
||||
}
|
||||
++FuncCoverage.LogicalLines;
|
||||
} else if (!LineExecs[Function] && Block->getCount()) {
|
||||
++FuncCoverage.LinesExec;
|
||||
LineExecs[Function] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LineCount == 0)
|
||||
CovOS << " #####:";
|
||||
else {
|
||||
CovOS << format("%9" PRIu64 ":", LineCount);
|
||||
++FileCoverage.LinesExec;
|
||||
}
|
||||
++FileCoverage.LogicalLines;
|
||||
|
||||
AllLines.printNext(CovOS, LineIndex + 1);
|
||||
|
||||
uint32_t BlockNo = 0;
|
||||
uint32_t EdgeNo = 0;
|
||||
for (const GCOVBlock *Block : Blocks) {
|
||||
// Only print block and branch information at the end of the block.
|
||||
if (Block->getLastLine() != LineIndex + 1)
|
||||
continue;
|
||||
if (Options.AllBlocks)
|
||||
printBlockInfo(CovOS, *Block, LineIndex, BlockNo);
|
||||
if (Options.BranchInfo) {
|
||||
size_t NumEdges = Block->getNumDstEdges();
|
||||
if (NumEdges > 1)
|
||||
printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo);
|
||||
else if (Options.UncondBranch && NumEdges == 1)
|
||||
printUncondBranchInfo(CovOS, EdgeNo,
|
||||
(*Block->dst_begin())->Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage));
|
||||
}
|
||||
|
||||
// FIXME: There is no way to detect calls given current instrumentation.
|
||||
if (Options.FuncCoverage)
|
||||
printFuncCoverage(InfoOS);
|
||||
printFileCoverage(InfoOS);
|
||||
}
|
||||
|
||||
/// printFunctionSummary - Print function and block summary.
|
||||
void FileInfo::printFunctionSummary(raw_ostream &OS,
|
||||
const FunctionVector &Funcs) const {
|
||||
for (const GCOVFunction *Func : Funcs) {
|
||||
uint64_t EntryCount = Func->getEntryCount();
|
||||
uint32_t BlocksExec = 0;
|
||||
for (const GCOVBlock &Block : Func->blocks())
|
||||
if (Block.getNumDstEdges() && Block.getCount())
|
||||
++BlocksExec;
|
||||
|
||||
OS << "function " << Func->getName() << " called " << EntryCount
|
||||
<< " returned " << safeDiv(Func->getExitCount() * 100, EntryCount)
|
||||
<< "% blocks executed "
|
||||
<< safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// printBlockInfo - Output counts for each block.
|
||||
void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
|
||||
uint32_t LineIndex, uint32_t &BlockNo) const {
|
||||
if (Block.getCount() == 0)
|
||||
OS << " $$$$$:";
|
||||
else
|
||||
OS << format("%9" PRIu64 ":", Block.getCount());
|
||||
OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++);
|
||||
}
|
||||
|
||||
/// printBranchInfo - Print conditional branch probabilities.
|
||||
void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
|
||||
GCOVCoverage &Coverage, uint32_t &EdgeNo) {
|
||||
SmallVector<uint64_t, 16> BranchCounts;
|
||||
uint64_t TotalCounts = 0;
|
||||
for (const GCOVEdge *Edge : Block.dsts()) {
|
||||
BranchCounts.push_back(Edge->Count);
|
||||
TotalCounts += Edge->Count;
|
||||
if (Block.getCount())
|
||||
++Coverage.BranchesExec;
|
||||
if (Edge->Count)
|
||||
++Coverage.BranchesTaken;
|
||||
++Coverage.Branches;
|
||||
|
||||
if (Options.FuncCoverage) {
|
||||
const GCOVFunction *Function = &Block.getParent();
|
||||
GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second;
|
||||
if (Block.getCount())
|
||||
++FuncCoverage.BranchesExec;
|
||||
if (Edge->Count)
|
||||
++FuncCoverage.BranchesTaken;
|
||||
++FuncCoverage.Branches;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint64_t N : BranchCounts)
|
||||
OS << format("branch %2u ", EdgeNo++)
|
||||
<< formatBranchInfo(Options, N, TotalCounts) << "\n";
|
||||
}
|
||||
|
||||
/// printUncondBranchInfo - Print unconditional branch probabilities.
|
||||
void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
|
||||
uint64_t Count) const {
|
||||
OS << format("unconditional %2u ", EdgeNo++)
|
||||
<< formatBranchInfo(Options, Count, Count) << "\n";
|
||||
}
|
||||
|
||||
// printCoverage - Print generic coverage info used by both printFuncCoverage
|
||||
// and printFileCoverage.
|
||||
void FileInfo::printCoverage(raw_ostream &OS,
|
||||
const GCOVCoverage &Coverage) const {
|
||||
OS << format("Lines executed:%.2f%% of %u\n",
|
||||
double(Coverage.LinesExec) * 100 / Coverage.LogicalLines,
|
||||
Coverage.LogicalLines);
|
||||
if (Options.BranchInfo) {
|
||||
if (Coverage.Branches) {
|
||||
OS << format("Branches executed:%.2f%% of %u\n",
|
||||
double(Coverage.BranchesExec) * 100 / Coverage.Branches,
|
||||
Coverage.Branches);
|
||||
OS << format("Taken at least once:%.2f%% of %u\n",
|
||||
double(Coverage.BranchesTaken) * 100 / Coverage.Branches,
|
||||
Coverage.Branches);
|
||||
} else {
|
||||
OS << "No branches\n";
|
||||
}
|
||||
OS << "No calls\n"; // to be consistent with gcov
|
||||
}
|
||||
}
|
||||
|
||||
// printFuncCoverage - Print per-function coverage info.
|
||||
void FileInfo::printFuncCoverage(raw_ostream &OS) const {
|
||||
for (const auto &FC : FuncCoverages) {
|
||||
const GCOVCoverage &Coverage = FC.second;
|
||||
OS << "Function '" << Coverage.Name << "'\n";
|
||||
printCoverage(OS, Coverage);
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// printFileCoverage - Print per-file coverage info.
|
||||
void FileInfo::printFileCoverage(raw_ostream &OS) const {
|
||||
for (const auto &FC : FileCoverages) {
|
||||
const std::string &Filename = FC.first;
|
||||
const GCOVCoverage &Coverage = FC.second;
|
||||
OS << "File '" << Coverage.Name << "'\n";
|
||||
printCoverage(OS, Coverage);
|
||||
if (!Options.NoOutput)
|
||||
OS << Coverage.Name << ":creating '" << Filename << "'\n";
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
@ -1,460 +0,0 @@
|
||||
//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header provides the interface to read and write coverage files that
|
||||
// use 'gcov' format.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_GCOV_H
|
||||
#define LLVM_PROFILEDATA_GCOV_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GCOVFunction;
|
||||
class GCOVBlock;
|
||||
class FileInfo;
|
||||
|
||||
namespace GCOV {
|
||||
|
||||
enum GCOVVersion { V402, V404, V704 };
|
||||
|
||||
/// \brief A struct for passing gcov options between functions.
|
||||
struct Options {
|
||||
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
|
||||
: AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
|
||||
PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
|
||||
|
||||
bool AllBlocks;
|
||||
bool BranchInfo;
|
||||
bool BranchCount;
|
||||
bool FuncCoverage;
|
||||
bool PreservePaths;
|
||||
bool UncondBranch;
|
||||
bool LongFileNames;
|
||||
bool NoOutput;
|
||||
};
|
||||
|
||||
} // end namespace GCOV
|
||||
|
||||
/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
|
||||
/// read operations.
|
||||
class GCOVBuffer {
|
||||
public:
|
||||
GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
|
||||
|
||||
/// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
|
||||
bool readGCNOFormat() {
|
||||
StringRef File = Buffer->getBuffer().slice(0, 4);
|
||||
if (File != "oncg") {
|
||||
errs() << "Unexpected file type: " << File << ".\n";
|
||||
return false;
|
||||
}
|
||||
Cursor = 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
|
||||
bool readGCDAFormat() {
|
||||
StringRef File = Buffer->getBuffer().slice(0, 4);
|
||||
if (File != "adcg") {
|
||||
errs() << "Unexpected file type: " << File << ".\n";
|
||||
return false;
|
||||
}
|
||||
Cursor = 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCOVVersion - Read GCOV version.
|
||||
bool readGCOVVersion(GCOV::GCOVVersion &Version) {
|
||||
StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (VersionStr == "*204") {
|
||||
Cursor += 4;
|
||||
Version = GCOV::V402;
|
||||
return true;
|
||||
}
|
||||
if (VersionStr == "*404") {
|
||||
Cursor += 4;
|
||||
Version = GCOV::V404;
|
||||
return true;
|
||||
}
|
||||
if (VersionStr == "*704") {
|
||||
Cursor += 4;
|
||||
Version = GCOV::V704;
|
||||
return true;
|
||||
}
|
||||
errs() << "Unexpected version: " << VersionStr << ".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
/// readFunctionTag - If cursor points to a function tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readFunctionTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
|
||||
Tag[3] != '\1') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readBlockTag - If cursor points to a block tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readBlockTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
|
||||
Tag[3] != '\x01') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readEdgeTag - If cursor points to an edge tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readEdgeTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
|
||||
Tag[3] != '\x01') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readLineTag - If cursor points to a line tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readLineTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
|
||||
Tag[3] != '\x01') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readArcTag - If cursor points to an gcda arc tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readArcTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
|
||||
Tag[3] != '\1') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readObjectTag - If cursor points to an object summary tag then increment
|
||||
/// the cursor and return true otherwise return false.
|
||||
bool readObjectTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
|
||||
Tag[3] != '\xa1') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readProgramTag - If cursor points to a program summary tag then increment
|
||||
/// the cursor and return true otherwise return false.
|
||||
bool readProgramTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
|
||||
Tag[3] != '\xa3') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readInt(uint32_t &Val) {
|
||||
if (Buffer->getBuffer().size() < Cursor + 4) {
|
||||
errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
|
||||
return false;
|
||||
}
|
||||
StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
Cursor += 4;
|
||||
Val = *(const uint32_t *)(Str.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readInt64(uint64_t &Val) {
|
||||
uint32_t Lo, Hi;
|
||||
if (!readInt(Lo) || !readInt(Hi))
|
||||
return false;
|
||||
Val = ((uint64_t)Hi << 32) | Lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readString(StringRef &Str) {
|
||||
uint32_t Len = 0;
|
||||
// Keep reading until we find a non-zero length. This emulates gcov's
|
||||
// behaviour, which appears to do the same.
|
||||
while (Len == 0)
|
||||
if (!readInt(Len))
|
||||
return false;
|
||||
Len *= 4;
|
||||
if (Buffer->getBuffer().size() < Cursor + Len) {
|
||||
errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
|
||||
return false;
|
||||
}
|
||||
Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
|
||||
Cursor += Len;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t getCursor() const { return Cursor; }
|
||||
void advanceCursor(uint32_t n) { Cursor += n * 4; }
|
||||
|
||||
private:
|
||||
MemoryBuffer *Buffer;
|
||||
uint64_t Cursor = 0;
|
||||
};
|
||||
|
||||
/// GCOVFile - Collects coverage information for one pair of coverage file
|
||||
/// (.gcno and .gcda).
|
||||
class GCOVFile {
|
||||
public:
|
||||
GCOVFile() = default;
|
||||
|
||||
bool readGCNO(GCOVBuffer &Buffer);
|
||||
bool readGCDA(GCOVBuffer &Buffer);
|
||||
uint32_t getChecksum() const { return Checksum; }
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
private:
|
||||
bool GCNOInitialized = false;
|
||||
GCOV::GCOVVersion Version;
|
||||
uint32_t Checksum = 0;
|
||||
SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
|
||||
uint32_t RunCount = 0;
|
||||
uint32_t ProgramCount = 0;
|
||||
};
|
||||
|
||||
/// GCOVEdge - Collects edge information.
|
||||
struct GCOVEdge {
|
||||
GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
|
||||
|
||||
GCOVBlock &Src;
|
||||
GCOVBlock &Dst;
|
||||
uint64_t Count = 0;
|
||||
};
|
||||
|
||||
/// GCOVFunction - Collects function information.
|
||||
class GCOVFunction {
|
||||
public:
|
||||
using BlockIterator = pointee_iterator<SmallVectorImpl<
|
||||
std::unique_ptr<GCOVBlock>>::const_iterator>;
|
||||
|
||||
GCOVFunction(GCOVFile &P) : Parent(P) {}
|
||||
|
||||
bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
|
||||
bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
|
||||
StringRef getName() const { return Name; }
|
||||
StringRef getFilename() const { return Filename; }
|
||||
size_t getNumBlocks() const { return Blocks.size(); }
|
||||
uint64_t getEntryCount() const;
|
||||
uint64_t getExitCount() const;
|
||||
|
||||
BlockIterator block_begin() const { return Blocks.begin(); }
|
||||
BlockIterator block_end() const { return Blocks.end(); }
|
||||
iterator_range<BlockIterator> blocks() const {
|
||||
return make_range(block_begin(), block_end());
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
private:
|
||||
GCOVFile &Parent;
|
||||
uint32_t Ident = 0;
|
||||
uint32_t Checksum;
|
||||
uint32_t LineNumber = 0;
|
||||
StringRef Name;
|
||||
StringRef Filename;
|
||||
SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
|
||||
SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
|
||||
};
|
||||
|
||||
/// GCOVBlock - Collects block information.
|
||||
class GCOVBlock {
|
||||
struct EdgeWeight {
|
||||
EdgeWeight(GCOVBlock *D) : Dst(D) {}
|
||||
|
||||
GCOVBlock *Dst;
|
||||
uint64_t Count = 0;
|
||||
};
|
||||
|
||||
struct SortDstEdgesFunctor {
|
||||
bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
|
||||
return E1->Dst.Number < E2->Dst.Number;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
|
||||
|
||||
GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
|
||||
~GCOVBlock();
|
||||
|
||||
const GCOVFunction &getParent() const { return Parent; }
|
||||
void addLine(uint32_t N) { Lines.push_back(N); }
|
||||
uint32_t getLastLine() const { return Lines.back(); }
|
||||
void addCount(size_t DstEdgeNo, uint64_t N);
|
||||
uint64_t getCount() const { return Counter; }
|
||||
|
||||
void addSrcEdge(GCOVEdge *Edge) {
|
||||
assert(&Edge->Dst == this); // up to caller to ensure edge is valid
|
||||
SrcEdges.push_back(Edge);
|
||||
}
|
||||
|
||||
void addDstEdge(GCOVEdge *Edge) {
|
||||
assert(&Edge->Src == this); // up to caller to ensure edge is valid
|
||||
// Check if adding this edge causes list to become unsorted.
|
||||
if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
|
||||
DstEdgesAreSorted = false;
|
||||
DstEdges.push_back(Edge);
|
||||
}
|
||||
|
||||
size_t getNumSrcEdges() const { return SrcEdges.size(); }
|
||||
size_t getNumDstEdges() const { return DstEdges.size(); }
|
||||
void sortDstEdges();
|
||||
|
||||
EdgeIterator src_begin() const { return SrcEdges.begin(); }
|
||||
EdgeIterator src_end() const { return SrcEdges.end(); }
|
||||
iterator_range<EdgeIterator> srcs() const {
|
||||
return make_range(src_begin(), src_end());
|
||||
}
|
||||
|
||||
EdgeIterator dst_begin() const { return DstEdges.begin(); }
|
||||
EdgeIterator dst_end() const { return DstEdges.end(); }
|
||||
iterator_range<EdgeIterator> dsts() const {
|
||||
return make_range(dst_begin(), dst_end());
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
private:
|
||||
GCOVFunction &Parent;
|
||||
uint32_t Number;
|
||||
uint64_t Counter = 0;
|
||||
bool DstEdgesAreSorted = true;
|
||||
SmallVector<GCOVEdge *, 16> SrcEdges;
|
||||
SmallVector<GCOVEdge *, 16> DstEdges;
|
||||
SmallVector<uint32_t, 16> Lines;
|
||||
};
|
||||
|
||||
class FileInfo {
|
||||
// It is unlikely--but possible--for multiple functions to be on the same
|
||||
// line.
|
||||
// Therefore this typedef allows LineData.Functions to store multiple
|
||||
// functions
|
||||
// per instance. This is rare, however, so optimize for the common case.
|
||||
using FunctionVector = SmallVector<const GCOVFunction *, 1>;
|
||||
using FunctionLines = DenseMap<uint32_t, FunctionVector>;
|
||||
using BlockVector = SmallVector<const GCOVBlock *, 4>;
|
||||
using BlockLines = DenseMap<uint32_t, BlockVector>;
|
||||
|
||||
struct LineData {
|
||||
LineData() = default;
|
||||
|
||||
BlockLines Blocks;
|
||||
FunctionLines Functions;
|
||||
uint32_t LastLine = 0;
|
||||
};
|
||||
|
||||
struct GCOVCoverage {
|
||||
GCOVCoverage(StringRef Name) : Name(Name) {}
|
||||
|
||||
StringRef Name;
|
||||
|
||||
uint32_t LogicalLines = 0;
|
||||
uint32_t LinesExec = 0;
|
||||
|
||||
uint32_t Branches = 0;
|
||||
uint32_t BranchesExec = 0;
|
||||
uint32_t BranchesTaken = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
FileInfo(const GCOV::Options &Options) : Options(Options) {}
|
||||
|
||||
void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
|
||||
if (Line > LineInfo[Filename].LastLine)
|
||||
LineInfo[Filename].LastLine = Line;
|
||||
LineInfo[Filename].Blocks[Line - 1].push_back(Block);
|
||||
}
|
||||
|
||||
void addFunctionLine(StringRef Filename, uint32_t Line,
|
||||
const GCOVFunction *Function) {
|
||||
if (Line > LineInfo[Filename].LastLine)
|
||||
LineInfo[Filename].LastLine = Line;
|
||||
LineInfo[Filename].Functions[Line - 1].push_back(Function);
|
||||
}
|
||||
|
||||
void setRunCount(uint32_t Runs) { RunCount = Runs; }
|
||||
void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
|
||||
void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
|
||||
StringRef GCDAFile);
|
||||
|
||||
private:
|
||||
std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
|
||||
std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
|
||||
void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
|
||||
void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
|
||||
uint32_t LineIndex, uint32_t &BlockNo) const;
|
||||
void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
|
||||
GCOVCoverage &Coverage, uint32_t &EdgeNo);
|
||||
void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
|
||||
uint64_t Count) const;
|
||||
|
||||
void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
|
||||
void printFuncCoverage(raw_ostream &OS) const;
|
||||
void printFileCoverage(raw_ostream &OS) const;
|
||||
|
||||
const GCOV::Options &Options;
|
||||
StringMap<LineData> LineInfo;
|
||||
uint32_t RunCount = 0;
|
||||
uint32_t ProgramCount = 0;
|
||||
|
||||
using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
|
||||
using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
|
||||
|
||||
FileCoverageList FileCoverages;
|
||||
FuncCoverageMap FuncCoverages;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_SUPPORT_GCOV_H
|
@ -47,10 +47,10 @@ iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
|
||||
try {
|
||||
is >> root;
|
||||
} catch (Json::RuntimeError &e) {
|
||||
LOG(ERROR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << "Could not open input file " << config_file_name;
|
||||
LOG(ERR) << "Could not open input file " << config_file_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,16 +77,18 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
|
||||
assert(arch_instr && "No instrumentation interface available but callback executed");
|
||||
auto entry = delays[instr_info.instr_id];
|
||||
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
|
||||
uint32_t delay = taken ? entry.taken : entry.not_taken;
|
||||
if(delay>1) arch_instr->set_curr_instr_cycles(delay);
|
||||
if (taken && entry.taken > 1)
|
||||
arch_instr->set_curr_instr_cycles(entry.taken);
|
||||
else if (entry.not_taken > 1)
|
||||
arch_instr->set_curr_instr_cycles(entry.not_taken);
|
||||
}
|
||||
|
@ -46,10 +46,10 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
|
||||
try {
|
||||
is >> root;
|
||||
} catch (Json::RuntimeError &e) {
|
||||
LOG(ERROR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << "Could not open input file " << config_file_name;
|
||||
LOG(ERR) << "Could not open input file " << config_file_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,11 +85,11 @@ bool iss::plugin::instruction_count::registration(const char* const version, vm_
|
||||
}
|
||||
rep_counts.resize(delays.size());
|
||||
} else {
|
||||
LOG(ERROR)<<"plugin instruction_count: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
|
||||
LOG(ERR)<<"plugin instruction_count: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info) {
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
|
||||
rep_counts[instr_info.instr_id]++;
|
||||
}
|
||||
|
@ -30,26 +30,67 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "sysc/core_complex.h"
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgf_c.h"
|
||||
#include "iss/debugger/encoderdecoder.h"
|
||||
#include "iss/debugger/gdb_session.h"
|
||||
#include "iss/debugger/server.h"
|
||||
#include "iss/debugger/target_adapter_if.h"
|
||||
#include "iss/iss.h"
|
||||
// clang-format off
|
||||
#include "iss/debugger/gdb_session.h"
|
||||
#include "iss/debugger/encoderdecoder.h"
|
||||
#include "iss/debugger/server.h"
|
||||
#include "iss/debugger/target_adapter_if.h"
|
||||
#include "iss/iss.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include "scc/report.h"
|
||||
#include <iss/plugin/loader.h>
|
||||
#include "sysc/core_complex.h"
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_mac.h"
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef WITH_SCV
|
||||
#include <array>
|
||||
#include <iss/plugin/cycle_estimate.h>
|
||||
#include <iss/plugin/instruction_count.h>
|
||||
// clang-format on
|
||||
|
||||
#define STR(X) #X
|
||||
#define CREATE_CORE(CN) \
|
||||
if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); } else
|
||||
|
||||
#ifdef HAS_SCV
|
||||
#include <scv.h>
|
||||
#else
|
||||
#include <scv-tr.h>
|
||||
using namespace scv_tr;
|
||||
#endif
|
||||
|
||||
#ifndef CWR_SYSTEMC
|
||||
#define GET_PROP_VALUE(P) P.get_value()
|
||||
#else
|
||||
#define GET_PROP_VALUE(P) P.getValue()
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
namespace sysc {
|
||||
namespace SiFive {
|
||||
namespace tgfs {
|
||||
using namespace std;
|
||||
using namespace iss;
|
||||
using namespace logging;
|
||||
@ -57,69 +98,42 @@ using namespace sc_core;
|
||||
|
||||
namespace {
|
||||
iss::debugger::encoder_decoder encdec;
|
||||
}
|
||||
|
||||
using core_type = iss::arch::tgf_c;
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
|
||||
std::array<const char*, 16> trap_str = { {
|
||||
"Instruction address misaligned",
|
||||
"Instruction access fault",
|
||||
"Illegal instruction",
|
||||
"Breakpoint",
|
||||
"Load address misaligned",
|
||||
"Load access fault",
|
||||
"Store/AMO address misaligned",
|
||||
"Store/AMO access fault",
|
||||
"Environment call from U-mode",
|
||||
"Environment call from S-mode",
|
||||
"Reserved",
|
||||
"Environment call from M-mode",
|
||||
"Instruction page fault",
|
||||
"Load page fault",
|
||||
"Reserved",
|
||||
"Store/AMO page fault"
|
||||
} };
|
||||
std::array<const char*, 12> irq_str = { {
|
||||
"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
|
||||
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
|
||||
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } };
|
||||
}
|
||||
|
||||
class core_wrapper : public iss::arch::riscv_hart_m_p<core_type> {
|
||||
template<typename PLAT>
|
||||
class core_wrapper_t : public PLAT {
|
||||
public:
|
||||
using base_type = arch::riscv_hart_m_p<core_type>;
|
||||
using phys_addr_t = typename arch::traits<core_type>::phys_addr_t;
|
||||
core_wrapper(core_complex *owner)
|
||||
using reg_t = typename arch::traits<typename PLAT::core>::reg_t;
|
||||
using phys_addr_t = typename arch::traits<typename PLAT::core>::phys_addr_t;
|
||||
using heart_state_t = typename PLAT::hart_state_type;
|
||||
core_wrapper_t(core_complex *owner)
|
||||
: owner(owner) { }
|
||||
|
||||
uint32_t get_mode() { return this->reg.machine_state; }
|
||||
uint32_t get_mode() { return this->reg.PRIV; }
|
||||
|
||||
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
|
||||
|
||||
inline bool get_interrupt_execution() { return this->interrupt_sim; }
|
||||
|
||||
base_type::hart_state<base_type::reg_t> &get_state() { return this->state; }
|
||||
heart_state_t &get_state() { return this->state; }
|
||||
|
||||
void notify_phase(exec_phase p) override {
|
||||
if (p == ISTART) owner->sync(this->reg.icount + cycle_offset);
|
||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
|
||||
}
|
||||
|
||||
sync_type needed_sync() const override { return PRE_SYNC; }
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
|
||||
if (!owner->disass_output(pc, instr)) {
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
|
||||
Log<Output2FILE<disass>>().get(INFO, "disass")
|
||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
|
||||
SCCDEBUG(owner->name())<<"disass: "
|
||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||
<< std::setfill(' ') << std::left << instr << s.str();
|
||||
}
|
||||
owner->disass_output(pc, instr);
|
||||
};
|
||||
|
||||
status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
|
||||
@ -146,6 +160,7 @@ public:
|
||||
}
|
||||
|
||||
status read_csr(unsigned addr, reg_t &val) override {
|
||||
#ifndef CWR_SYSTEMC
|
||||
if((addr==arch::time || addr==arch::timeh) && owner->mtime_o.get_interface(0)){
|
||||
uint64_t time_val;
|
||||
bool ret = owner->mtime_o->nb_peek(time_val);
|
||||
@ -156,21 +171,32 @@ public:
|
||||
val = static_cast<reg_t>(time_val >> 32);
|
||||
}
|
||||
return ret?Ok:Err;
|
||||
#else
|
||||
if((addr==arch::time || addr==arch::timeh)){
|
||||
uint64_t time_val = owner->mtime_i.read();
|
||||
if (addr == iss::arch::time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if (addr == iss::arch::timeh) {
|
||||
if (sizeof(reg_t) != 4) return iss::Err;
|
||||
val = static_cast<reg_t>(time_val >> 32);
|
||||
}
|
||||
return Ok;
|
||||
#endif
|
||||
} else {
|
||||
return base_type::read_csr(addr, val);
|
||||
return PLAT::read_csr(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_until(uint64_t flags) override {
|
||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||
do {
|
||||
wait(wfi_evt);
|
||||
sc_core::wait(wfi_evt);
|
||||
} while (this->reg.pending_trap == 0);
|
||||
base_type::wait_until(flags);
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
void local_irq(short id, bool value) {
|
||||
base_type::reg_t mask = 0;
|
||||
reg_t mask = 0;
|
||||
switch (id) {
|
||||
case 16: // SW
|
||||
mask = 1 << 3;
|
||||
@ -191,6 +217,8 @@ public:
|
||||
} else
|
||||
this->csr[arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -228,19 +256,98 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func
|
||||
return Err;
|
||||
}
|
||||
|
||||
core_complex::core_complex(sc_module_name name)
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
class core_wrapper {
|
||||
public:
|
||||
core_wrapper(core_complex *owner) : owner(owner) { }
|
||||
|
||||
void reset(uint64_t addr){vm->reset(addr);}
|
||||
inline void start(){vm->start();}
|
||||
inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
|
||||
|
||||
std::function<unsigned(void)> get_mode;
|
||||
std::function<uint64_t(void)> get_state;
|
||||
std::function<bool(void)> get_interrupt_execution;
|
||||
std::function<void(bool)> set_interrupt_execution;
|
||||
std::function<void(short, bool)> local_irq;
|
||||
|
||||
template<typename PLAT>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
|
||||
auto* lcpu = new core_wrapper_t<PLAT>(owner);
|
||||
lcpu->set_mhartid(hart_id);
|
||||
get_mode = [lcpu]() { return lcpu->get_mode(); };
|
||||
get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
|
||||
get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
|
||||
set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
|
||||
local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_TCC
|
||||
if(backend == "tcc")
|
||||
s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
|
||||
CREATE_CORE(tgc_c)
|
||||
#ifdef CORE_TGC_B
|
||||
CREATE_CORE(tgc_b)
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
CREATE_CORE(tgc_d)
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MACD
|
||||
CREATE_CORE(tgc_d_xrb_mac)
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
|
||||
}
|
||||
auto *srv = debugger::server<debugger::gdb_session>::get();
|
||||
if (srv) tgt_adapter = srv->get_target();
|
||||
if (tgt_adapter)
|
||||
tgt_adapter->add_custom_command(
|
||||
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
|
||||
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
|
||||
"SystemC sub-commands: break <time>, print_time"});
|
||||
|
||||
}
|
||||
|
||||
core_complex * const owner;
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
|
||||
};
|
||||
|
||||
struct core_trace {
|
||||
//! transaction recording database
|
||||
scv_tr_db *m_db{nullptr};
|
||||
//! blocking transaction recording stream handle
|
||||
scv_tr_stream *stream_handle{nullptr};
|
||||
//! transaction generator handle for blocking transactions
|
||||
scv_tr_generator<_scv_tr_generator_default_data, _scv_tr_generator_default_data> *instr_tr_handle{nullptr};
|
||||
scv_tr_handle tr_handle;
|
||||
};
|
||||
|
||||
SC_HAS_PROCESS(core_complex);// NOLINT
|
||||
#ifndef CWR_SYSTEMC
|
||||
core_complex::core_complex(sc_module_name const& name)
|
||||
: sc_module(name)
|
||||
, read_lut(tlm_dmi_ext())
|
||||
, write_lut(tlm_dmi_ext())
|
||||
, tgt_adapter(nullptr)
|
||||
#ifdef WITH_SCV
|
||||
, m_db(scv_tr_db::get_default_db())
|
||||
, stream_handle(nullptr)
|
||||
, instr_tr_handle(nullptr)
|
||||
, fetch_tr_handle(nullptr)
|
||||
#endif
|
||||
{
|
||||
SC_HAS_PROCESS(core_complex);// NOLINT
|
||||
init();
|
||||
}
|
||||
#endif
|
||||
|
||||
void core_complex::init(){
|
||||
trc=new core_trace();
|
||||
initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||
auto lut_entry = read_lut.getEntry(start);
|
||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
|
||||
@ -253,8 +360,6 @@ core_complex::core_complex(sc_module_name name)
|
||||
});
|
||||
|
||||
SC_THREAD(run);
|
||||
SC_METHOD(clk_cb);
|
||||
sensitive << clk_i;
|
||||
SC_METHOD(rst_cb);
|
||||
sensitive << rst_i;
|
||||
SC_METHOD(sw_irq_cb);
|
||||
@ -263,82 +368,115 @@ core_complex::core_complex(sc_module_name name)
|
||||
sensitive << timer_irq_i;
|
||||
SC_METHOD(global_irq_cb);
|
||||
sensitive << global_irq_i;
|
||||
trc->m_db=scv_tr_db::get_default_db();
|
||||
|
||||
SC_METHOD(forward);
|
||||
#ifndef CWR_SYSTEMC
|
||||
sensitive<<clk_i;
|
||||
#else
|
||||
sensitive<<curr_clk;
|
||||
t2t.reset(new scc::tick2time{"t2t"});
|
||||
t2t->clk_i(clk_i);
|
||||
t2t->clk_o(curr_clk);
|
||||
#endif
|
||||
}
|
||||
|
||||
core_complex::~core_complex() = default;
|
||||
core_complex::~core_complex(){
|
||||
delete cpu;
|
||||
delete trc;
|
||||
for (auto *p : plugin_list)
|
||||
delete p;
|
||||
}
|
||||
|
||||
void core_complex::trace(sc_trace_file *trf) const {}
|
||||
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
vm_ptr create_cpu(core_wrapper* cpu, std::string const& backend, unsigned gdb_port){
|
||||
if(backend == "interp")
|
||||
return vm_ptr{iss::interp::create<core_type>(cpu, gdb_port)};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return vm_ptr{iss::llvm::create(lcpu, gdb_port)};
|
||||
#endif
|
||||
if(backend == "tcc")
|
||||
return vm_ptr{iss::tcc::create<core_type>(cpu, gdb_port)};
|
||||
return {nullptr};
|
||||
}
|
||||
|
||||
void core_complex::before_end_of_elaboration() {
|
||||
SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend";
|
||||
cpu = scc::make_unique<core_wrapper>(this);
|
||||
cpu->set_mhartid(mhartid.get_value());
|
||||
SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<GET_PROP_VALUE(backend)<<" backend";
|
||||
// cpu = scc::make_unique<core_wrapper>(this);
|
||||
cpu = new core_wrapper(this);
|
||||
cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid));
|
||||
sc_assert(cpu->vm!=nullptr);
|
||||
cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr);
|
||||
if (GET_PROP_VALUE(plugins).length()) {
|
||||
auto p = util::split(GET_PROP_VALUE(plugins), ';');
|
||||
for (std::string const& opt_val : p) {
|
||||
std::string plugin_name=opt_val;
|
||||
std::string filename{"cycles.txt"};
|
||||
std::size_t found = opt_val.find('=');
|
||||
if (found != std::string::npos) {
|
||||
plugin_name = opt_val.substr(0, found);
|
||||
filename = opt_val.substr(found + 1, opt_val.size());
|
||||
}
|
||||
if (plugin_name == "ic") {
|
||||
auto *plugin = new iss::plugin::instruction_count(filename);
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else if (plugin_name == "ce") {
|
||||
auto *plugin = new iss::plugin::cycle_estimate(filename);
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
if(plugin){
|
||||
cpu->vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else
|
||||
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm = create_cpu(cpu.get(), backend.get_value(), gdb_server_port.get_value());
|
||||
#ifdef WITH_SCV
|
||||
vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
|
||||
#else
|
||||
vm->setDisassEnabled(enable_disass.get_value());
|
||||
#endif
|
||||
auto *srv = debugger::server<debugger::gdb_session>::get();
|
||||
if (srv) tgt_adapter = srv->get_target();
|
||||
if (tgt_adapter)
|
||||
tgt_adapter->add_custom_command(
|
||||
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
|
||||
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
|
||||
"SystemC sub-commands: break <time>, print_time"});
|
||||
}
|
||||
|
||||
void core_complex::start_of_simulation() {
|
||||
quantum_keeper.reset();
|
||||
if (elf_file.get_value().size() > 0) {
|
||||
istringstream is(elf_file.get_value());
|
||||
if (GET_PROP_VALUE(elf_file).size() > 0) {
|
||||
istringstream is(GET_PROP_VALUE(elf_file));
|
||||
string s;
|
||||
while (getline(is, s, ',')) {
|
||||
std::pair<uint64_t, bool> start_addr = cpu->load_file(s);
|
||||
#ifndef CWR_SYSTEMC
|
||||
if (reset_address.is_default_value() && start_addr.second == true)
|
||||
reset_address.set_value(start_addr.first);
|
||||
#else
|
||||
if (start_addr.second == true)
|
||||
reset_address=start_addr.first;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef WITH_SCV
|
||||
if (m_db != nullptr && stream_handle == nullptr) {
|
||||
if (trc->m_db != nullptr && trc->stream_handle == nullptr) {
|
||||
string basename(this->name());
|
||||
stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", m_db);
|
||||
instr_tr_handle = new scv_tr_generator<>("execute", *stream_handle);
|
||||
fetch_tr_handle = new scv_tr_generator<uint64_t>("fetch", *stream_handle);
|
||||
trc->stream_handle = new scv_tr_stream((basename + ".instr").c_str(), "TRANSACTOR", trc->m_db);
|
||||
trc->instr_tr_handle = new scv_tr_generator<>("execute", *trc->stream_handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
if (trc->m_db == nullptr) return false;
|
||||
if (trc->tr_handle.is_active()) trc->tr_handle.end_transaction();
|
||||
trc->tr_handle = trc->instr_tr_handle->begin_transaction();
|
||||
trc->tr_handle.record_attribute("PC", pc);
|
||||
trc->tr_handle.record_attribute("INSTR", instr_str);
|
||||
trc->tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]);
|
||||
trc->tr_handle.record_attribute("MSTATUS", cpu->get_state());
|
||||
trc->tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
void core_complex::forward() {
|
||||
#ifndef CWR_SYSTEMC
|
||||
set_clock_period(clk_i.read());
|
||||
#else
|
||||
set_clock_period(curr_clk.read());
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void core_complex::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
#ifdef WITH_SCV
|
||||
if (m_db == nullptr) return;
|
||||
if (tr_handle.is_active()) tr_handle.end_transaction();
|
||||
tr_handle = instr_tr_handle->begin_transaction();
|
||||
tr_handle.record_attribute("PC", pc);
|
||||
tr_handle.record_attribute("INSTR", instr_str);
|
||||
tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]);
|
||||
tr_handle.record_attribute("MSTATUS", cpu->get_state().mstatus.st.value);
|
||||
tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void core_complex::clk_cb() {
|
||||
curr_clk = clk_i.read();
|
||||
if (curr_clk == SC_ZERO_TIME) cpu->set_interrupt_execution(true);
|
||||
void core_complex::set_clock_period(sc_core::sc_time period) {
|
||||
curr_clk = period;
|
||||
if (period == SC_ZERO_TIME) cpu->set_interrupt_execution(true);
|
||||
}
|
||||
|
||||
void core_complex::rst_cb() {
|
||||
@ -355,14 +493,14 @@ void core_complex::run() {
|
||||
wait(SC_ZERO_TIME); // separate from elaboration phase
|
||||
do {
|
||||
if (rst_i.read()) {
|
||||
cpu->reset(reset_address.get_value());
|
||||
cpu->reset(GET_PROP_VALUE(reset_address));
|
||||
wait(rst_i.negedge_event());
|
||||
}
|
||||
while (clk_i.read() == SC_ZERO_TIME) {
|
||||
wait(clk_i.value_changed_event());
|
||||
while (curr_clk.read() == SC_ZERO_TIME) {
|
||||
wait(curr_clk.value_changed_event());
|
||||
}
|
||||
cpu->set_interrupt_execution(false);
|
||||
vm->start();
|
||||
cpu->start();
|
||||
} while (cpu->get_interrupt_execution());
|
||||
sc_stop();
|
||||
}
|
||||
@ -382,16 +520,14 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
gp.set_data_ptr(data);
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
sc_time delay{quantum_keeper.get_local_time()};
|
||||
#ifdef WITH_SCV
|
||||
if (m_db != nullptr && tr_handle.is_valid()) {
|
||||
if (is_fetch && tr_handle.is_active()) {
|
||||
tr_handle.end_transaction();
|
||||
sc_time delay=quantum_keeper.get_local_time();
|
||||
if (trc->m_db != nullptr && trc->tr_handle.is_valid()) {
|
||||
if (is_fetch && trc->tr_handle.is_active()) {
|
||||
trc->tr_handle.end_transaction();
|
||||
}
|
||||
auto preExt = new scv4tlm::tlm_recording_extension(tr_handle, this);
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
#endif
|
||||
initiator->b_transport(gp, delay);
|
||||
SCCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
|
||||
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
||||
@ -431,13 +567,11 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
gp.set_data_ptr(write_buf.data());
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
sc_time delay{quantum_keeper.get_local_time()};
|
||||
#ifdef WITH_SCV
|
||||
if (m_db != nullptr && tr_handle.is_valid()) {
|
||||
auto preExt = new scv4tlm::tlm_recording_extension(tr_handle, this);
|
||||
sc_time delay=quantum_keeper.get_local_time();
|
||||
if (trc->m_db != nullptr && trc->tr_handle.is_valid()) {
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
#endif
|
||||
initiator->b_transport(gp, delay);
|
||||
quantum_keeper.set(delay);
|
||||
SCCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
|
||||
@ -500,6 +634,5 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
|
||||
return initiator->transport_dbg(gp) == length;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace SiFive */
|
||||
} /* namespace sysc */
|
||||
|
1
src/vm/interp/.gitignore
vendored
Normal file
1
src/vm/interp/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/vm_tgc_*.cpp
|
4291
src/vm/interp/vm_tgc_c.cpp
Normal file
4291
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
File diff suppressed because it is too large
Load Diff
@ -377,7 +377,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 2);
|
||||
gen_trap_check(tu);
|
||||
@ -424,7 +423,6 @@ private:
|
||||
new_pc_val,
|
||||
tu.l_not(tu.constant(0x1, 32U))), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 3);
|
||||
@ -466,7 +464,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 4);
|
||||
gen_trap_check(tu);
|
||||
@ -507,7 +504,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 5);
|
||||
gen_trap_check(tu);
|
||||
@ -552,7 +548,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 6);
|
||||
gen_trap_check(tu);
|
||||
@ -597,7 +592,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 7);
|
||||
gen_trap_check(tu);
|
||||
@ -638,7 +632,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 8);
|
||||
gen_trap_check(tu);
|
||||
@ -679,7 +672,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 9);
|
||||
gen_trap_check(tu);
|
||||
@ -1621,7 +1613,6 @@ private:
|
||||
tu.constant(1, 64U),
|
||||
tu.trunc(tu.constant(imm, 32U), 32));
|
||||
tu.close_scope();
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
gen_set_pc(tu, pc, traits<ARCH>::NEXT_PC);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 38);
|
||||
gen_trap_check(tu);
|
||||
@ -2055,13 +2046,11 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
@ -2070,7 +2059,6 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
|
@ -449,7 +449,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 2);
|
||||
gen_trap_check(tu);
|
||||
@ -487,7 +486,6 @@ private:
|
||||
new_pc_val,
|
||||
tu.l_not(tu.constant(0x1, 32U))), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 3);
|
||||
gen_trap_check(tu);
|
||||
@ -528,7 +526,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 4);
|
||||
gen_trap_check(tu);
|
||||
@ -569,7 +566,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 5);
|
||||
gen_trap_check(tu);
|
||||
@ -614,7 +610,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 6);
|
||||
gen_trap_check(tu);
|
||||
@ -659,7 +654,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 7);
|
||||
gen_trap_check(tu);
|
||||
@ -700,7 +694,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 8);
|
||||
gen_trap_check(tu);
|
||||
@ -741,7 +734,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 9);
|
||||
gen_trap_check(tu);
|
||||
@ -1683,7 +1675,6 @@ private:
|
||||
tu.constant(1, 64U),
|
||||
tu.trunc(tu.constant(imm, 32U), 32));
|
||||
tu.close_scope();
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
gen_set_pc(tu, pc, traits<ARCH>::NEXT_PC);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 38);
|
||||
gen_trap_check(tu);
|
||||
@ -2562,7 +2553,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 65);
|
||||
gen_trap_check(tu);
|
||||
@ -2868,7 +2858,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 76);
|
||||
gen_trap_check(tu);
|
||||
@ -2908,7 +2897,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 77);
|
||||
gen_trap_check(tu);
|
||||
@ -2948,7 +2936,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 78);
|
||||
gen_trap_check(tu);
|
||||
@ -3055,7 +3042,6 @@ private:
|
||||
tu.open_scope();
|
||||
auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits<ARCH>::X0, 0), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 82);
|
||||
gen_trap_check(tu);
|
||||
@ -3108,7 +3094,6 @@ private:
|
||||
tu.constant(2, 32U)), 1 + traits<ARCH>::X0);
|
||||
auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits<ARCH>::X0, 0), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 84);
|
||||
gen_trap_check(tu);
|
||||
@ -3247,13 +3232,11 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
@ -3262,7 +3245,6 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user