Compare commits
117 Commits
feature/re
...
c792f50427
Author | SHA1 | Date | |
---|---|---|---|
c792f50427 | |||
6ed7eafc5d | |||
8a5fe58d51 | |||
16cd6d5ff5 | |||
ee2ded931d | |||
95ba5c901a | |||
32848ec396 | |||
6789cf4c32 | |||
3bc4884a9d | |||
fd6b738168 | |||
afdf8fb97f | |||
cfa7b72363 | |||
d330307ed5 | |||
916de2a26d | |||
aa70d8a54a | |||
b493745cd7 | |||
f9e8e1d857 | |||
974d64a627 | |||
d70489cbb8 | |||
d990f1cf5d | |||
1672b01e62 | |||
00b0f101ac | |||
54f75f92ea | |||
0304aac9e5 | |||
8ff55d7b92 | |||
f626ee2684 | |||
a8a2782329 | |||
98dd329833 | |||
6213445bc4 | |||
c5465bf9e2 | |||
d881cb6e63 | |||
2e4faa4d50 | |||
8e1951f298 | |||
7efa924510 | |||
febbc4fff0 | |||
39b2788b7e | |||
a943dd3bdf | |||
fedbff5971 | |||
c2758e8321 | |||
8be5fe71df | |||
3f7ce41b9d | |||
ad1cbedf00 | |||
83f54b5074 | |||
a83928fd8c | |||
ec55efd322 | |||
8c3709f92a | |||
207dbf1071 | |||
62c118e501 | |||
65dca13b42 | |||
3187cbdfe2 | |||
8c701d55c1 | |||
f585489ff5 | |||
7113683ee0 | |||
1a0fc4bd5d | |||
40d1966e9a | |||
a977200284 | |||
b20fd3eba5 | |||
b20daa1ac2 | |||
b1a18459e7 | |||
6ba7c82f80 | |||
ad7bb28b4c | |||
fa7eda0889 | |||
00e02bf565 | |||
1ad66a71d8 | |||
e60fa3d5e6 | |||
8407f6287f | |||
0833198d34 | |||
57347ae4d9 | |||
4876f18ba9 | |||
a53ee42e13 | |||
12ccfc055a | |||
feaa49d367 | |||
18f33b4a68 | |||
f096b15dbd | |||
cb5375258a | |||
076b5a39ad | |||
f40ab41899 | |||
e8fd5143bc | |||
31fb51de95 | |||
5d481eb79d | |||
1c90fe765d | |||
52ed8b81a6 | |||
0703a0a845 | |||
0c542d42aa | |||
966d1616c5 | |||
1720bd4aaa | |||
df16378605 | |||
1438f0f373 | |||
766f3ba9ee | |||
5da4e6b424 | |||
e382217e04 | |||
9db4e3fd87 | |||
bb658be3b4 | |||
6579780dc9 | |||
e56bc12788 | |||
e88f309ea2 | |||
03bec27376 | |||
9d9008a3a2 | |||
5f6d462973 | |||
a92b84bef4 | |||
477c530847 | |||
c054d75717 | |||
15cd26f800 | |||
9465cffe79 | |||
00d2d06cbd | |||
8e4e702cb9 | |||
49be143588 | |||
0aea1d0177 | |||
6ea7721961 | |||
b0cb997009 | |||
9dfca612b7 | |||
30ae743361 | |||
d91f5f9df4 | |||
5ec457c76b | |||
2e670c4d03 | |||
3d32c33333 | |||
521f40a3d6 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,6 +30,5 @@ language.settings.xml
|
|||||||
/.gdbinit
|
/.gdbinit
|
||||||
/*.out
|
/*.out
|
||||||
/dump.json
|
/dump.json
|
||||||
/src-gen/
|
|
||||||
/*.yaml
|
/*.yaml
|
||||||
/*.json
|
/*.json
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "gen_input/CoreDSL-Instruction-Set-Description"]
|
|
||||||
path = gen_input/CoreDSL-Instruction-Set-Description
|
|
||||||
url = ../CoreDSL-Instruction-Set-Description.git
|
|
@ -6,8 +6,9 @@ project(dbt-rise-tgc VERSION 1.0.0)
|
|||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
find_package(elfio)
|
find_package(elfio QUIET)
|
||||||
find_package(Boost COMPONENTS coroutine)
|
find_package(Boost COMPONENTS coroutine)
|
||||||
|
find_package(jsoncpp)
|
||||||
|
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
if(DEFINED ENV{LLVM_HOME})
|
if(DEFINED ENV{LLVM_HOME})
|
||||||
@ -28,34 +29,40 @@ endif()
|
|||||||
|
|
||||||
add_subdirectory(softfloat)
|
add_subdirectory(softfloat)
|
||||||
|
|
||||||
# library files
|
|
||||||
FILE(GLOB TGC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp)
|
|
||||||
FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
|
|
||||||
|
|
||||||
set(LIB_SOURCES
|
set(LIB_SOURCES
|
||||||
|
src/iss/plugin/instruction_count.cpp
|
||||||
|
src/iss/arch/tgc_c.cpp
|
||||||
|
src/vm/interp/vm_tgc_c.cpp
|
||||||
src/vm/fp_functions.cpp
|
src/vm/fp_functions.cpp
|
||||||
src/plugin/instruction_count.cpp
|
|
||||||
src/plugin/pctrace.cpp
|
|
||||||
|
|
||||||
${TGC_SOURCES}
|
|
||||||
${TGC_VM_SOURCES}
|
|
||||||
)
|
)
|
||||||
if(TARGET RapidJSON)
|
|
||||||
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp)
|
# library files
|
||||||
|
if(TARGET ${CORE_NAME}_cpp)
|
||||||
|
list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
|
||||||
|
else()
|
||||||
|
FILE(GLOB GEN_SOURCES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
|
||||||
|
)
|
||||||
|
list(APPEND LIB_SOURCES ${GEN_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
|
||||||
|
list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
FILE(GLOB TGC_LLVM_SOURCES
|
FILE(GLOB LLVM_GEN_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/llvm/vm_*.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp
|
||||||
)
|
)
|
||||||
list(APPEND LIB_SOURCES ${TGC_LLVM_SOURCES})
|
list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_TCC)
|
if(WITH_TCC)
|
||||||
FILE(GLOB TGC_TCC_SOURCES
|
FILE(GLOB TCC_GEN_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
|
||||||
)
|
)
|
||||||
list(APPEND LIB_SOURCES ${TGC_TCC_SOURCES})
|
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Define the library
|
# Define the library
|
||||||
@ -70,21 +77,31 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
|||||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC incl)
|
target_include_directories(${PROJECT_NAME} PUBLIC src)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp Boost::coroutine)
|
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util Boost::coroutine)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
if(TARGET jsoncpp::jsoncpp)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp::jsoncpp)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-core)
|
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp)
|
||||||
endif()
|
endif()
|
||||||
if(TARGET CONAN_PKG::elfio)
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND BUILD_SHARED_LIBS)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC CONAN_PKG::elfio)
|
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-rise-core -Wl,--no-whole-archive)
|
||||||
elseif(TARGET elfio::elfio)
|
else()
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core)
|
||||||
|
endif()
|
||||||
|
if(TARGET elfio::elfio)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
|
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||||
endif()
|
endif()
|
||||||
if(TARGET RapidJSON)
|
if(TARGET lz4::lz4)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4)
|
||||||
|
endif()
|
||||||
|
if(TARGET RapidJSON::RapidJSON)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON::RapidJSON)
|
||||||
|
elseif(TARGET RapidJSON)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -114,16 +131,31 @@ project(tgc-sim)
|
|||||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||||
|
if(TARGET ${CORE_NAME}_cpp)
|
||||||
|
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
|
||||||
|
else()
|
||||||
|
FILE(GLOB TGC_SOURCES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
|
||||||
|
)
|
||||||
|
list(APPEND TGC_SOURCES ${GEN_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
foreach(F IN LISTS TGC_SOURCES)
|
foreach(F IN LISTS TGC_SOURCES)
|
||||||
|
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||||
endif()
|
endif()
|
||||||
|
if(WITH_TCC)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
|
||||||
|
endif()
|
||||||
# Links the target exe against the libraries
|
# Links the target exe against the libraries
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
|
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
|
||||||
if(TARGET Boost::program_options)
|
if(TARGET Boost::program_options)
|
||||||
@ -148,24 +180,24 @@ install(TARGETS tgc-sim
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
if(TARGET scc-sysc)
|
||||||
|
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
||||||
include(SystemCPackage)
|
|
||||||
if(SystemC_FOUND)
|
|
||||||
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
|
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
|
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||||
foreach(F IN LISTS TGC_SOURCES)
|
foreach(F IN LISTS TGC_SOURCES)
|
||||||
|
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
|
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/core_complex.h)
|
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
FRAMEWORK FALSE
|
FRAMEWORK FALSE
|
||||||
|
3
contrib/.gitignore
vendored
Normal file
3
contrib/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/results
|
||||||
|
/cwr
|
||||||
|
/*.xml
|
43
contrib/README.md
Normal file
43
contrib/README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Notes
|
||||||
|
|
||||||
|
* requires conan version 1.59
|
||||||
|
* requires decent cmake version 3.23
|
||||||
|
|
||||||
|
Setup for tcsh:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
|
||||||
|
cd TGC-ISS/
|
||||||
|
setenv TGFS_INSTALL_ROOT `pwd`/install
|
||||||
|
setenv COWAREHOME <your SNPS PA installation>
|
||||||
|
setenv SNPSLMD_LICENSE_FILE <your SNPS PA license file>
|
||||||
|
source $COWAREHOME/SLS/linux/setup.csh pae
|
||||||
|
setenv SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM 1
|
||||||
|
setenv PATH $COWAREHOME/common/bin/:${PATH}
|
||||||
|
setenv CC $COWAREHOME/SLS/linux/common/bin/gcc
|
||||||
|
setenv CXX $COWAREHOME/SLS/linux/common/bin/g++
|
||||||
|
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
|
||||||
|
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
|
||||||
|
cmake --build build/PA --target install -j16
|
||||||
|
cd dbt-rise-tgc/contrib
|
||||||
|
# import the TGC core itself
|
||||||
|
pct tgc_import_tb.tcl
|
||||||
|
```
|
||||||
|
|
||||||
|
Setup for bash:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone --recursive -b develop https://git.minres.com/TGFS/TGC-ISS.git
|
||||||
|
cd TGC-ISS/
|
||||||
|
export TGFS_INSTALL_ROOT `pwd`/install
|
||||||
|
module load tools/pa/T-2022.06
|
||||||
|
export SNPS_ENABLE_MEM_ON_DEMAND_IN_GENERIC_MEM=1
|
||||||
|
export CC=$COWAREHOME/SLS/linux/common/bin/gcc
|
||||||
|
export CXX=$COWAREHOME/SLS/linux/common/bin/g++
|
||||||
|
cmake -S . -B build/PA -DCMAKE_BUILD_TYPE=Debug -DUSE_CWR_SYSTEMC=ON -DBUILD_SHARED_LIBS=ON \
|
||||||
|
-DCODEGEN=OFF -DCMAKE_INSTALL_PREFIX=${TGFS_INSTALL_ROOT}
|
||||||
|
cmake --build build/PA --target install -j16
|
||||||
|
cd dbt-rise-tgc/contrib
|
||||||
|
# import the TGC core itself
|
||||||
|
pct tgc_import_tb.tcl
|
||||||
|
```
|
@ -16,7 +16,7 @@ namespace eval Specification {
|
|||||||
set libdir "${install_dir}/lib64"
|
set libdir "${install_dir}/lib64"
|
||||||
set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"]
|
set preprocessorOptions [concat $preprocessorOptions "-I${incldir}"]
|
||||||
# Set the Linker paths.
|
# Set the Linker paths.
|
||||||
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc"]
|
set linkerOptions [concat $linkerOptions "-Wl,-rpath,${libdir} -L${libdir} -ldbt-rise-tgc_sc -lscc-sysc"]
|
||||||
}
|
}
|
||||||
default {
|
default {
|
||||||
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"
|
puts stderr "ERROR: \"$target\" is not supported, [::scsh::version]"
|
||||||
|
2092
contrib/hello.dis
Normal file
2092
contrib/hello.dis
Normal file
File diff suppressed because it is too large
Load Diff
BIN
contrib/hello.elf
Executable file
BIN
contrib/hello.elf
Executable file
Binary file not shown.
BIN
contrib/minres.png
Executable file
BIN
contrib/minres.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -6,14 +6,11 @@ proc getScriptDirectory {} {
|
|||||||
set scriptFolder [file dirname $dispScriptFile]
|
set scriptFolder [file dirname $dispScriptFile]
|
||||||
return $scriptFolder
|
return $scriptFolder
|
||||||
}
|
}
|
||||||
if { $::env(SNPS_VP_PRODUCT) == "PAULTRA" } {
|
|
||||||
set hardware /HARDWARE/HW/HW
|
set hardware /HARDWARE/HW/HW
|
||||||
} else {
|
|
||||||
set hardware /HARDWARE
|
|
||||||
}
|
|
||||||
|
|
||||||
set scriptDir [getScriptDirectory]
|
set scriptDir [getScriptDirectory]
|
||||||
set top_design_name core_complex
|
set top_design_name core_complex
|
||||||
|
set encap_name sysc::tgfs::${top_design_name}
|
||||||
set clocks clk_i
|
set clocks clk_i
|
||||||
set resets rst_i
|
set resets rst_i
|
||||||
set model_prefix "i_"
|
set model_prefix "i_"
|
||||||
@ -28,7 +25,8 @@ set model_postfix ""
|
|||||||
::pct::set_update_existing_encaps_flag true
|
::pct::set_update_existing_encaps_flag true
|
||||||
::pct::set_dynamic_port_arrays_flag true
|
::pct::set_dynamic_port_arrays_flag true
|
||||||
::pct::set_import_scml_properties_flag true
|
::pct::set_import_scml_properties_flag true
|
||||||
::pct::load_modules --set-category modules tgc_import.cc
|
::pct::set_import_encap_prop_as_extra_prop_flag true
|
||||||
|
::pct::load_modules --set-category modules ${scriptDir}/tgc_import.cc
|
||||||
|
|
||||||
# Set Port Protocols correctly
|
# Set Port Protocols correctly
|
||||||
set block ${top_design_name}
|
set block ${top_design_name}
|
||||||
@ -38,13 +36,15 @@ foreach clock ${clocks} {
|
|||||||
foreach reset ${resets} {
|
foreach reset ${resets} {
|
||||||
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET
|
::pct::set_block_port_protocol --set-category SYSTEM_LIBRARY:$block/${reset} SYSTEM_LIBRARY:RESET
|
||||||
}
|
}
|
||||||
::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16
|
#::pct::set_encap_port_array_size SYSTEM_LIBRARY:$block/local_irq_i 16
|
||||||
|
|
||||||
# Set compile settings and look
|
# Set compile settings and look
|
||||||
set block SYSTEM_LIBRARY:${top_design_name}
|
set block SYSTEM_LIBRARY:${top_design_name}
|
||||||
::pct::set_encap_build_script $block/${top_design_name} $scriptDir/build.tcl
|
::pct::set_encap_build_script $block/${encap_name} $scriptDir/build.tcl
|
||||||
::pct::set_background_color_rgb $block 255 255 255 255
|
::pct::set_background_color_rgb $block 255 255 255 255
|
||||||
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${top_design_name}
|
::pct::create_instance SYSTEM_LIBRARY:${top_design_name} ${hardware} ${model_prefix}${top_design_name}${model_postfix} ${encap_name} ${encap_name}()
|
||||||
|
::pct::set_bounds i_${top_design_name} 200 300 100 400
|
||||||
|
::pct::set_image i_${top_design_name} "$scriptDir/minres.png" center center false true
|
||||||
|
|
||||||
# export the result as component
|
# export the result as component
|
||||||
::pct::export_system_library ${top_design_name} ${top_design_name}.xml
|
::pct::export_system_library ${top_design_name} ${top_design_name}.xml
|
||||||
|
71
contrib/tgc_import_tb.tcl
Normal file
71
contrib/tgc_import_tb.tcl
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
source tgc_import.tcl
|
||||||
|
set hardware /HARDWARE/HW/HW
|
||||||
|
set FW_name ${scriptDir}/hello.elf
|
||||||
|
|
||||||
|
puts "instantiate testbench elements"
|
||||||
|
::paultra::add_hw_instance GenericIPlib:Memory_Generic -inst_name i_Memory_Generic
|
||||||
|
::pct::set_param_value i_Memory_Generic/MEM:protocol {Protocol Common Parameters} address_width 30
|
||||||
|
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/LT/clock_period_in_ns 1
|
||||||
|
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/read/cmd_accept_cycles 1
|
||||||
|
::pct::set_param_value i_Memory_Generic {Scml Properties} /timing/write/cmd_accept_cycles 1
|
||||||
|
::pct::set_bounds i_Memory_Generic 1000 300 100 100
|
||||||
|
|
||||||
|
::paultra::add_hw_instance Bus:Bus -inst_name i_Bus
|
||||||
|
::BLWizard::generateFramework i_Bus SBLTLM2FT * {} \
|
||||||
|
{ common_configuration:BackBone:/advanced/num_resources_per_target:1 }
|
||||||
|
::pct::set_bounds i_Bus 700 300 100 400
|
||||||
|
::pct::create_connection C_ibus i_core_complex/ibus i_Bus/i_core_complex_ibus
|
||||||
|
::pct::set_location_on_owner i_Bus/i_core_complex_ibus 10
|
||||||
|
::pct::create_connection C_dbus i_core_complex/dbus i_Bus/i_core_complex_dbus
|
||||||
|
::pct::set_location_on_owner i_Bus/i_core_complex_dbus 10
|
||||||
|
::pct::create_connection C_mem i_Bus/i_Memory_Generic_MEM i_Memory_Generic/MEM
|
||||||
|
|
||||||
|
puts "instantiating clock manager"
|
||||||
|
set clock "Clk"
|
||||||
|
::hw::create_hw_instance "" GenericIPlib:ClockGenerator ${clock}_clock
|
||||||
|
::pct::set_bounds ${clock}_clock 100 100 100 100
|
||||||
|
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period 1000
|
||||||
|
::pct::set_param_value $hardware/${clock}_clock {Constructor Arguments} period_unit sc_core::SC_PS
|
||||||
|
|
||||||
|
puts "instantiating reset manager"
|
||||||
|
set reset "Rst"
|
||||||
|
::hw::create_hw_instance "" GenericIPlib:ResetGenerator ${reset}_reset
|
||||||
|
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time 0
|
||||||
|
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} start_time_unit sc_core::SC_PS
|
||||||
|
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration 10000
|
||||||
|
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} duration_unit sc_core::SC_PS
|
||||||
|
::pct::set_param_value $hardware/${reset}_reset {Constructor Arguments} active_level true
|
||||||
|
::pct::set_bounds ${reset}_reset 300 100 100 100
|
||||||
|
|
||||||
|
puts "connecting reset/clock"
|
||||||
|
::pct::create_connection C_clk . Clk_clock/CLK i_core_complex/clk_i
|
||||||
|
::pct::add_ports_to_connection C_clk i_Bus/Clk
|
||||||
|
::pct::add_ports_to_connection C_clk i_Memory_Generic/CLK
|
||||||
|
::pct::create_connection C_rst . Rst_reset/RST i_core_complex/rst_i
|
||||||
|
::pct::add_ports_to_connection C_rst i_Bus/Rst
|
||||||
|
|
||||||
|
puts "setting parameters for DBT-RISE-TGC/Bus and memory components"
|
||||||
|
::pct::set_param_value $hardware/i_${top_design_name} {Extra properties} elf_file ${FW_name}
|
||||||
|
::pct::set_address $hardware/i_${top_design_name}/ibus:i_Memory_Generic/MEM 0x0
|
||||||
|
::pct::set_address $hardware/i_${top_design_name}/dbus:i_Memory_Generic/MEM 0x0
|
||||||
|
::BLWizard::updateFramework i_Bus {} { common_configuration:BackBone:/advanced/num_resources_per_target:1 }
|
||||||
|
|
||||||
|
::pct::set_main_configuration Default {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::INFO).coloredOutput(false).logAsync(false));} {} {} {}}
|
||||||
|
::pct::set_main_configuration Debug {{#include <scc/report.h>} {::scc::init_logging(::scc::LogConfig().logLevel(::scc::log::DEBUG).coloredOutput(false).logAsync(false));} {} {} {}}
|
||||||
|
::pct::create_simulation_build_config Debug
|
||||||
|
::pct::set_simulation_build_project_setting Debug "Main Configuration" Default
|
||||||
|
# add build settings and save design for next steps
|
||||||
|
#::pct::set_simulation_build_project_setting "Debug" "Linker Flags" "-Wl,-z,muldefs $::env(VERILATOR_ROOT)/include/verilated.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_sc.cpp $::env(VERILATOR_ROOT)/include/verilated_vcd_c.cpp"
|
||||||
|
#::pct::set_simulation_build_project_setting "Debug" "Include Paths" $::env(VERILATOR_ROOT)/include/
|
||||||
|
|
||||||
|
#::simulation::set_simulation_property Simulation [list run_for_duration:200ns results_dir:results/test_0 "TLM Port Trace:true"]
|
||||||
|
#::simulation::run_simulation Simulation
|
||||||
|
|
||||||
|
#::pct::set_simulation_build_project_setting Debug {Export Type} {STATIC NETLIST}
|
||||||
|
#::pct::set_simulation_build_project_setting Debug {Encapsulated Netlist} false
|
||||||
|
#::pct::export_system "export"
|
||||||
|
#::cd "export"
|
||||||
|
#::scsh::open-project
|
||||||
|
#::scsh::build
|
||||||
|
#::scsh::elab sim
|
||||||
|
::pct::save_system testbench.xml
|
1
gen_input/.gitignore
vendored
1
gen_input/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/src-gen/
|
/src-gen/
|
||||||
|
/CoreDSL-Instruction-Set-Description
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
import "RV32I.core_desc"
|
||||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
import "RVM.core_desc"
|
||||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
import "RVC.core_desc"
|
||||||
|
|
||||||
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||||
architectural_state {
|
architectural_state {
|
||||||
|
@ -33,13 +33,13 @@
|
|||||||
def getRegisterSizes(){
|
def getRegisterSizes(){
|
||||||
def regs = registers.collect{it.size}
|
def regs = registers.collect{it.size}
|
||||||
regs[-1]=64 // correct for NEXT_PC
|
regs[-1]=64 // correct for NEXT_PC
|
||||||
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||||
return regs
|
return regs
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
#include "${coreDef.name.toLowerCase()}.h"
|
||||||
#include "util/ities.h"
|
#include "util/ities.h"
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -51,9 +51,7 @@ constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::a
|
|||||||
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_bit_widths;
|
||||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
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()}() {
|
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default;
|
||||||
reg.icount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
|
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
|
||||||
|
|
||||||
@ -64,8 +62,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
|
|||||||
reg.PC=address;
|
reg.PC=address;
|
||||||
reg.NEXT_PC=reg.PC;
|
reg.NEXT_PC=reg.PC;
|
||||||
reg.PRIV=0x3;
|
reg.PRIV=0x3;
|
||||||
reg.trap_state=0;
|
trap_state=0;
|
||||||
reg.icount=0;
|
icount=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
|
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
|
||||||
|
@ -37,7 +37,7 @@ def nativeTypeSize(int size){
|
|||||||
}
|
}
|
||||||
def getRegisterSizes(){
|
def getRegisterSizes(){
|
||||||
def regs = registers.collect{nativeTypeSize(it.size)}
|
def regs = registers.collect{nativeTypeSize(it.size)}
|
||||||
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||||
return regs
|
return regs
|
||||||
}
|
}
|
||||||
def getRegisterOffsets(){
|
def getRegisterOffsets(){
|
||||||
@ -91,12 +91,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
|||||||
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
||||||
|
|
||||||
enum reg_e {
|
enum reg_e {
|
||||||
${registers.collect{it.name}.join(', ')}, NUM_REGS,
|
${registers.collect{it.name}.join(', ')}, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||||
TRAP_STATE=NUM_REGS,
|
|
||||||
PENDING_TRAP,
|
|
||||||
ICOUNT,
|
|
||||||
CYCLE,
|
|
||||||
INSTRET
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using reg_t = uint${addrDataWidth}_t;
|
using reg_t = uint${addrDataWidth}_t;
|
||||||
@ -141,7 +136,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
|||||||
|
|
||||||
uint8_t* get_regs_base_ptr() override;
|
uint8_t* get_regs_base_ptr() override;
|
||||||
|
|
||||||
inline uint64_t get_icount() { return reg.icount; }
|
inline uint64_t get_icount() { return icount; }
|
||||||
|
|
||||||
inline bool should_stop() { return interrupt_sim; }
|
inline bool should_stop() { return interrupt_sim; }
|
||||||
|
|
||||||
@ -159,7 +154,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
|||||||
|
|
||||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||||
|
|
||||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
inline uint32_t get_last_branch() { return last_branch; }
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -169,10 +164,18 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
|||||||
}}%>
|
}}%>
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
|
uint64_t cycle = 0;
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t last_branch;
|
uint32_t instruction = 0;
|
||||||
|
uint32_t last_branch = 0;
|
||||||
} reg;
|
} reg;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
|
uint64_t icount = 0;
|
||||||
|
uint64_t cycle = 0;
|
||||||
|
uint64_t instret = 0;
|
||||||
|
uint32_t instruction = 0;
|
||||||
|
uint32_t last_branch = 0;
|
||||||
std::array<address_type, 4> addr_mode;
|
std::array<address_type, 4> addr_mode;
|
||||||
|
|
||||||
uint64_t interrupt_sim=0;
|
uint64_t interrupt_sim=0;
|
||||||
|
86
gen_input/templates/CORENAME_decoder.cpp.gtl
Normal file
86
gen_input/templates/CORENAME_decoder.cpp.gtl
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "${coreDef.name.toLowerCase()}.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace arch {
|
||||||
|
namespace {
|
||||||
|
// according to
|
||||||
|
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||||
|
#ifdef __GCC__
|
||||||
|
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
||||||
|
#elif __cplusplus < 201402L
|
||||||
|
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
||||||
|
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
||||||
|
#else
|
||||||
|
constexpr size_t bit_count(uint32_t u) {
|
||||||
|
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||||
|
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* start opcode definitions
|
||||||
|
****************************************************************************/
|
||||||
|
struct instruction_desriptor {
|
||||||
|
size_t length;
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t mask;
|
||||||
|
opcode_e op;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<instruction_desriptor, ${instructions.size}> instr_descr = {{
|
||||||
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, opcode_e::${instr.instruction.name}},<%}%>
|
||||||
|
}};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct instruction_decoder<${coreDef.name.toLowerCase()}> {
|
||||||
|
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
|
||||||
|
using code_word_t=traits<${coreDef.name.toLowerCase()}>::code_word_t;
|
||||||
|
|
||||||
|
struct instruction_pattern {
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t mask;
|
||||||
|
opcode_e id;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
unsigned decode_instruction(T);
|
||||||
|
|
||||||
|
instruction_decoder() {
|
||||||
|
for (auto instr : instr_descr) {
|
||||||
|
auto quadrant = instr.value & 0x3;
|
||||||
|
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
||||||
|
}
|
||||||
|
for(auto& lut: qlut){
|
||||||
|
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
|
||||||
|
return bit_count(a.mask) < bit_count(b.mask);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned instruction_decoder<${coreDef.name.toLowerCase()}>::decode_instruction<traits<${coreDef.name.toLowerCase()}>::code_word_t>(traits<${coreDef.name.toLowerCase()}>::code_word_t instr){
|
||||||
|
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||||
|
return !((instr&e.mask) ^ e.value );
|
||||||
|
});
|
||||||
|
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<instruction_decoder<${coreDef.name.toLowerCase()}>> traits<${coreDef.name.toLowerCase()}>::get_decoder(){
|
||||||
|
return std::make_unique<instruction_decoder<${coreDef.name.toLowerCase()}>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -12,5 +12,6 @@
|
|||||||
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
|
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
|
||||||
- ${it.instruction.name}:
|
- ${it.instruction.name}:
|
||||||
encoding: ${it.encoding}
|
encoding: ${it.encoding}
|
||||||
mask: ${it.mask}<%}}%>
|
mask: ${it.mask}<%if(it.attributes.size) {%>
|
||||||
|
attributes: ${it.attributes}<%}}}%>
|
||||||
|
|
||||||
|
@ -36,11 +36,10 @@ def nativeTypeSize(int size){
|
|||||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
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/gdb_session.h>
|
||||||
#include <iss/debugger/server.h>
|
#include <iss/debugger/server.h>
|
||||||
|
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||||
|
#include <iss/arch/riscv_hart_m_p.h>
|
||||||
#include <iss/iss.h>
|
#include <iss/iss.h>
|
||||||
#include <iss/interp/vm_base.h>
|
#include <iss/interp/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
@ -73,6 +72,7 @@ public:
|
|||||||
using addr_t = typename super::addr_t;
|
using addr_t = typename super::addr_t;
|
||||||
using reg_t = typename traits::reg_t;
|
using reg_t = typename traits::reg_t;
|
||||||
using mem_type_e = typename traits::mem_type_e;
|
using mem_type_e = typename traits::mem_type_e;
|
||||||
|
using opcode_e = typename traits::opcode_e;
|
||||||
|
|
||||||
vm_impl();
|
vm_impl();
|
||||||
|
|
||||||
@ -92,9 +92,9 @@ protected:
|
|||||||
using compile_ret_t = virt_addr_t;
|
using compile_ret_t = virt_addr_t;
|
||||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
||||||
|
|
||||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
|
||||||
|
|
||||||
compile_func decode_inst(code_word_t instr) ;
|
typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr);
|
||||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||||
|
|
||||||
// some compile time constants
|
// some compile time constants
|
||||||
@ -114,15 +114,15 @@ protected:
|
|||||||
struct instruction_pattern {
|
struct instruction_pattern {
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func opc;
|
typename arch::traits<ARCH>::opcode_e id;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||||
|
|
||||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||||
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
|
this->core.trap_state = trap_val;
|
||||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void leave(unsigned lvl){
|
inline void leave(unsigned lvl){
|
||||||
@ -137,44 +137,6 @@ protected:
|
|||||||
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
|
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
|
||||||
std::vector<coro_t> spawn_blocks;
|
std::vector<coro_t> spawn_blocks;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
|
|
||||||
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
|
|
||||||
auto ret = super::template read_mem<uint8_t>(space, addr);
|
|
||||||
if(this->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>
|
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||||
inline S sext(U from) {
|
inline S sext(U from) {
|
||||||
auto mask = (1ULL<<W) - 1;
|
auto mask = (1ULL<<W) - 1;
|
||||||
@ -183,6 +145,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void process_spawn_blocks() {
|
inline void process_spawn_blocks() {
|
||||||
|
if(spawn_blocks.size()==0) return;
|
||||||
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
|
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
|
||||||
if(*it){
|
if(*it){
|
||||||
(*it)();
|
(*it)();
|
||||||
@ -193,6 +156,7 @@ protected:
|
|||||||
<%functions.each{ it.eachLine { %>
|
<%functions.each{ it.eachLine { %>
|
||||||
${it}<%}%>
|
${it}<%}%>
|
||||||
<%}%>
|
<%}%>
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
@ -201,74 +165,14 @@ private:
|
|||||||
size_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
typename arch::traits<ARCH>::opcode_e op;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
/* instruction ${instr.instruction.name} */
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${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
|
|
||||||
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}
|
|
||||||
<%}%>
|
|
||||||
}
|
|
||||||
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
|
||||||
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
|
||||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
|
||||||
// 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
|
|
||||||
process_spawn_blocks();
|
|
||||||
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;
|
//static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||||
auto phys_pc = this->core.v2p(pc);
|
auto phys_pc = this->core.v2p(pc);
|
||||||
@ -307,6 +211,7 @@ constexpr size_t bit_count(uint32_t u) {
|
|||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||||
|
unsigned id=0;
|
||||||
for (auto instr : instr_descr) {
|
for (auto instr : instr_descr) {
|
||||||
auto quadrant = instr.value & 0x3;
|
auto quadrant = instr.value & 0x3;
|
||||||
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
||||||
@ -327,39 +232,82 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
|
typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
|
||||||
for(auto& e: qlut[instr&0x3]){
|
for(auto& e: qlut[instr&0x3]){
|
||||||
if(!((instr&e.mask) ^ e.value )) return e.opc;
|
if(!((instr&e.mask) ^ e.value )) return e.id;
|
||||||
}
|
}
|
||||||
return &this_class::illegal_intruction;
|
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
||||||
// we fetch at max 4 byte, alignment is 2
|
|
||||||
code_word_t insn = 0;
|
|
||||||
auto *const data = (uint8_t *)&insn;
|
|
||||||
auto pc=start;
|
auto pc=start;
|
||||||
|
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||||
|
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||||
|
auto& trap_state = this->core.trap_state;
|
||||||
|
auto& icount = this->core.icount;
|
||||||
|
auto& cycle = this->core.cycle;
|
||||||
|
auto& instret = this->core.instret;
|
||||||
|
auto& instr = this->core.instruction;
|
||||||
|
// we fetch at max 4 byte, alignment is 2
|
||||||
|
auto *const data = reinterpret_cast<uint8_t*>(&instr);
|
||||||
|
|
||||||
while(!this->core.should_stop() &&
|
while(!this->core.should_stop() &&
|
||||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||||
auto res = fetch_ins(pc, data);
|
if(fetch_ins(pc, data)!=iss::Ok){
|
||||||
if(res!=iss::Ok){
|
|
||||||
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
|
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);
|
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
|
||||||
} else {
|
} else {
|
||||||
if (is_jump_to_self_enabled(cond) &&
|
if (is_jump_to_self_enabled(cond) &&
|
||||||
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||||
auto f = decode_inst(insn);
|
auto inst_id = decode_inst_id(instr);
|
||||||
auto old_pc = pc.val;
|
// pre execution stuff
|
||||||
pc = (this->*f)(pc, insn);
|
this->core.last_branch = 0;
|
||||||
|
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
|
||||||
|
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
|
case arch::traits<ARCH>::opcode_e::${instr.name}: {
|
||||||
|
<%instr.fields.eachLine{%>${it}
|
||||||
|
<%}%>if(this->disass_enabled){
|
||||||
|
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||||
|
${it}<%}%>
|
||||||
|
}
|
||||||
|
// used registers<%instr.usedVariables.each{ k,v->
|
||||||
|
if(v.isArray) {%>
|
||||||
|
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
|
||||||
|
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
|
||||||
|
<%}}%>// calculate next pc value
|
||||||
|
*NEXT_PC = *PC + ${instr.length/8};
|
||||||
|
// execute instruction<%instr.behavior.eachLine{%>
|
||||||
|
${it}<%}%>
|
||||||
|
TRAP_${instr.name}:break;
|
||||||
|
}// @suppress("No break at end of case")<%}%>
|
||||||
|
default: {
|
||||||
|
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||||
|
raise(0, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// post execution stuff
|
||||||
|
process_spawn_blocks();
|
||||||
|
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
|
||||||
|
// if(!this->core.trap_state) // update trap state if there is a pending interrupt
|
||||||
|
// this->core.trap_state = this->core.pending_trap;
|
||||||
|
// trap check
|
||||||
|
if(trap_state!=0){
|
||||||
|
super::core.enter_trap(trap_state, pc.val, instr);
|
||||||
|
} else {
|
||||||
|
icount++;
|
||||||
|
instret++;
|
||||||
|
}
|
||||||
|
cycle++;
|
||||||
|
pc.val=*NEXT_PC;
|
||||||
this->core.reg.PC = this->core.reg.NEXT_PC;
|
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||||
this->core.reg.trap_state = this->core.reg.pending_trap;
|
this->core.trap_state = this->core.pending_trap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mnrv32
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||||
|
@ -30,10 +30,10 @@
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
|
||||||
#include <iss/arch/riscv_hart_m_p.h>
|
|
||||||
#include <iss/debugger/gdb_session.h>
|
#include <iss/debugger/gdb_session.h>
|
||||||
#include <iss/debugger/server.h>
|
#include <iss/debugger/server.h>
|
||||||
|
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||||
|
#include <iss/arch/riscv_hart_m_p.h>
|
||||||
#include <iss/iss.h>
|
#include <iss/iss.h>
|
||||||
#include <iss/llvm/vm_base.h>
|
#include <iss/llvm/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
|
@ -55,10 +55,12 @@ using namespace iss::debugger;
|
|||||||
|
|
||||||
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
|
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
|
||||||
public:
|
public:
|
||||||
|
using traits = arch::traits<ARCH>;
|
||||||
using super = typename iss::tcc::vm_base<ARCH>;
|
using super = typename iss::tcc::vm_base<ARCH>;
|
||||||
using virt_addr_t = typename super::virt_addr_t;
|
using virt_addr_t = typename super::virt_addr_t;
|
||||||
using phys_addr_t = typename super::phys_addr_t;
|
using phys_addr_t = typename super::phys_addr_t;
|
||||||
using code_word_t = typename super::code_word_t;
|
using code_word_t = typename super::code_word_t;
|
||||||
|
using mem_type_e = typename traits::mem_type_e;
|
||||||
using addr_t = typename super::addr_t;
|
using addr_t = typename super::addr_t;
|
||||||
using tu_builder = typename super::tu_builder;
|
using tu_builder = typename super::tu_builder;
|
||||||
|
|
||||||
@ -82,7 +84,7 @@ protected:
|
|||||||
using compile_ret_t = std::tuple<continuation_e>;
|
using compile_ret_t = std::tuple<continuation_e>;
|
||||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
|
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
|
||||||
|
|
||||||
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||||
|
|
||||||
void setup_module(std::string m) override {
|
void setup_module(std::string m) override {
|
||||||
super::setup_module(m);
|
super::setup_module(m);
|
||||||
@ -104,10 +106,10 @@ protected:
|
|||||||
|
|
||||||
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
|
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
|
||||||
switch(reg_num){
|
switch(reg_num){
|
||||||
case traits<ARCH>::NEXT_PC:
|
case traits::NEXT_PC:
|
||||||
tu("*next_pc = {:#x};", pc.val);
|
tu("*next_pc = {:#x};", pc.val);
|
||||||
break;
|
break;
|
||||||
case traits<ARCH>::PC:
|
case traits::PC:
|
||||||
tu("*pc = {:#x};", pc.val);
|
tu("*pc = {:#x};", pc.val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -123,7 +125,7 @@ protected:
|
|||||||
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
||||||
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
|
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
|
||||||
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
|
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
|
||||||
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
|
enum { LUT_SIZE = 1 << util::bit_count(static_cast<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> lut;
|
||||||
|
|
||||||
@ -170,6 +172,12 @@ protected:
|
|||||||
}
|
}
|
||||||
return lut_val;
|
return lut_val;
|
||||||
}
|
}
|
||||||
|
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||||
|
inline S sext(U from) {
|
||||||
|
auto mask = (1ULL<<W) - 1;
|
||||||
|
auto sign_mask = 1ULL<<(W-1);
|
||||||
|
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -185,14 +193,27 @@ private:
|
|||||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
||||||
{${instr.length}, 0b${instr.value}, 0b${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||||
}};
|
}};
|
||||||
|
|
||||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
/* instruction ${idx}: ${instr.name} */
|
/* instruction ${idx}: ${instr.name} */
|
||||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){<%instr.code.eachLine{%>
|
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||||
|
tu("${instr.name}_{:#010x}:", pc.val);
|
||||||
|
vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
|
||||||
|
<%instr.fields.eachLine{%>${it}
|
||||||
|
<%}%>if(this->disass_enabled){
|
||||||
|
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||||
${it}<%}%>
|
${it}<%}%>
|
||||||
}
|
}
|
||||||
|
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
||||||
|
pc=pc+4;
|
||||||
|
tu.open_scope();<%instr.behavior.eachLine{%>
|
||||||
|
${it}<%}%>
|
||||||
|
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
||||||
|
gen_trap_check(tu);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
<%}%>
|
<%}%>
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* end opcode definitions
|
* end opcode definitions
|
||||||
@ -233,7 +254,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|||||||
// we fetch at max 4 byte, alignment is 2
|
// we fetch at max 4 byte, alignment is 2
|
||||||
enum {TRAP_ID=1<<16};
|
enum {TRAP_ID=1<<16};
|
||||||
code_word_t insn = 0;
|
code_word_t insn = 0;
|
||||||
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
|
const typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||||
phys_addr_t paddr(pc);
|
phys_addr_t paddr(pc);
|
||||||
auto *const data = (uint8_t *)&insn;
|
auto *const data = (uint8_t *)&insn;
|
||||||
paddr = this->core.v2p(pc);
|
paddr = this->core.v2p(pc);
|
||||||
@ -260,13 +281,13 @@ 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) {
|
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(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||||
tu("leave_trap(core_ptr, {});", 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(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
|
||||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||||
@ -274,8 +295,8 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
|||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||||
tu("trap_entry:");
|
tu("trap_entry:");
|
||||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
|
||||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
|
||||||
tu("return *next_pc;");
|
tu("return *next_pc;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
incl/iss/arch/.gitignore
vendored
1
incl/iss/arch/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/tgc_*.h
|
|
@ -8,7 +8,7 @@ project("sotfloat" VERSION 3.0.0)
|
|||||||
# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
|
# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
|
||||||
set(VERSION "3e")
|
set(VERSION "3e")
|
||||||
|
|
||||||
include(Common)
|
#include(Common)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(SPECIALIZATION RISCV)
|
set(SPECIALIZATION RISCV)
|
||||||
|
2
src-gen/.gitignore
vendored
Normal file
2
src-gen/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/iss
|
||||||
|
/vm
|
100
src/iss/arch/hwl.h
Normal file
100
src/iss/arch/hwl.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2022 MINRES Technologies GmbH
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* eyck@minres.com - initial implementation
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _RISCV_HART_M_P_HWL_H
|
||||||
|
#define _RISCV_HART_M_P_HWL_H
|
||||||
|
|
||||||
|
#include <iss/vm_types.h>
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace arch {
|
||||||
|
|
||||||
|
template <typename BASE> class hwl : public BASE {
|
||||||
|
public:
|
||||||
|
using base_class = BASE;
|
||||||
|
using this_class = hwl<BASE>;
|
||||||
|
using reg_t = typename BASE::reg_t;
|
||||||
|
|
||||||
|
hwl();
|
||||||
|
virtual ~hwl() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
iss::status read_custom_csr_reg(unsigned addr, reg_t &val) override;
|
||||||
|
iss::status write_custom_csr_reg(unsigned addr, reg_t val) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline hwl<BASE>::hwl() {
|
||||||
|
for (unsigned addr = 0x800; addr < 0x803; ++addr){
|
||||||
|
this->register_custom_csr_rd(addr);
|
||||||
|
this->register_custom_csr_wr(addr);
|
||||||
|
}
|
||||||
|
for (unsigned addr = 0x804; addr < 0x807; ++addr){
|
||||||
|
this->register_custom_csr_rd(addr);
|
||||||
|
this->register_custom_csr_wr(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t &val) {
|
||||||
|
switch(addr){
|
||||||
|
case 0x800: val = this->reg.lpstart0; break;
|
||||||
|
case 0x801: val = this->reg.lpend0; break;
|
||||||
|
case 0x802: val = this->reg.lpcount0; break;
|
||||||
|
case 0x804: val = this->reg.lpstart1; break;
|
||||||
|
case 0x805: val = this->reg.lpend1; break;
|
||||||
|
case 0x806: val = this->reg.lpcount1; break;
|
||||||
|
}
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
|
||||||
|
switch(addr){
|
||||||
|
case 0x800: this->reg.lpstart0 = val; break;
|
||||||
|
case 0x801: this->reg.lpend0 = val; break;
|
||||||
|
case 0x802: this->reg.lpcount0 = val; break;
|
||||||
|
case 0x804: this->reg.lpstart1 = val; break;
|
||||||
|
case 0x805: this->reg.lpend1 = val; break;
|
||||||
|
case 0x806: this->reg.lpcount1 = val; break;
|
||||||
|
}
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arch
|
||||||
|
} // namespace iss
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _RISCV_HART_M_P_H */
|
@ -43,7 +43,7 @@ namespace arch {
|
|||||||
|
|
||||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
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 features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8, FEAT_TCM=16};
|
||||||
|
|
||||||
enum riscv_csr {
|
enum riscv_csr {
|
||||||
/* user-level CSR */
|
/* user-level CSR */
|
||||||
@ -51,12 +51,18 @@ enum riscv_csr {
|
|||||||
ustatus = 0x000,
|
ustatus = 0x000,
|
||||||
uie = 0x004,
|
uie = 0x004,
|
||||||
utvec = 0x005,
|
utvec = 0x005,
|
||||||
|
utvt = 0x007, //CLIC
|
||||||
// User Trap Handling
|
// User Trap Handling
|
||||||
uscratch = 0x040,
|
uscratch = 0x040,
|
||||||
uepc = 0x041,
|
uepc = 0x041,
|
||||||
ucause = 0x042,
|
ucause = 0x042,
|
||||||
utval = 0x043,
|
utval = 0x043,
|
||||||
uip = 0x044,
|
uip = 0x044,
|
||||||
|
uxnti = 0x045, //CLIC
|
||||||
|
uintstatus = 0xCB1, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||||
|
uintthresh = 0x047, // MRW Interrupt-level threshold (CLIC) - addr subject to change
|
||||||
|
uscratchcsw = 0x048, // MRW Conditional scratch swap on priv mode change (CLIC)
|
||||||
|
uscratchcswl = 0x049, // MRW Conditional scratch swap on level change (CLIC)
|
||||||
// User Floating-Point CSRs
|
// User Floating-Point CSRs
|
||||||
fflags = 0x001,
|
fflags = 0x001,
|
||||||
frm = 0x002,
|
frm = 0x002,
|
||||||
@ -114,11 +120,10 @@ enum riscv_csr {
|
|||||||
mtval = 0x343,
|
mtval = 0x343,
|
||||||
mip = 0x344,
|
mip = 0x344,
|
||||||
mxnti = 0x345, //CLIC
|
mxnti = 0x345, //CLIC
|
||||||
mintstatus = 0x346, // MRW Current interrupt levels (CLIC) - addr subject to change
|
mintstatus = 0xFB1, // MRW Current interrupt levels (CLIC) - addr subject to change
|
||||||
|
mintthresh = 0x347, // MRW Interrupt-level threshold (CLIC) - addr subject to change
|
||||||
mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
|
mscratchcsw = 0x348, // MRW Conditional scratch swap on priv mode change (CLIC)
|
||||||
mscratchcswl = 0x349, // MRW Conditional scratch swap on level 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
|
// Physical Memory Protection
|
||||||
pmpcfg0 = 0x3A0,
|
pmpcfg0 = 0x3A0,
|
||||||
pmpcfg1 = 0x3A1,
|
pmpcfg1 = 0x3A1,
|
||||||
@ -188,7 +193,7 @@ enum {
|
|||||||
|
|
||||||
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
|
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 { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3, PRIV_D = 4};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ISA_A = 1,
|
ISA_A = 1,
|
||||||
@ -214,6 +219,15 @@ struct vm_info {
|
|||||||
bool is_active() { return levels; }
|
bool is_active() { return levels; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct feature_config {
|
||||||
|
uint64_t clic_base{0xc0000000};
|
||||||
|
unsigned clic_int_ctl_bits{4};
|
||||||
|
unsigned clic_num_irq{16};
|
||||||
|
unsigned clic_num_trigger{0};
|
||||||
|
uint64_t tcm_base{0x10000000};
|
||||||
|
uint64_t tcm_size{0x8000};
|
||||||
|
};
|
||||||
|
|
||||||
class trap_load_access_fault : public trap_access {
|
class trap_load_access_fault : public trap_access {
|
||||||
public:
|
public:
|
||||||
trap_load_access_fault(uint64_t badaddr)
|
trap_load_access_fault(uint64_t badaddr)
|
||||||
@ -239,6 +253,49 @@ public:
|
|||||||
trap_store_page_fault(uint64_t badaddr)
|
trap_store_page_fault(uint64_t badaddr)
|
||||||
: trap_access(15 << 16, badaddr) {}
|
: trap_access(15 << 16, badaddr) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void read_reg_uint32(uint64_t offs, uint32_t& reg, uint8_t *const data, unsigned length) {
|
||||||
|
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||||
|
switch (offs & 0x3) {
|
||||||
|
case 0:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(data + i) = *(reg_ptr + i);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(data + i) = *(reg_ptr + 1 + i);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(data + i) = *(reg_ptr + 2 + i);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*data = *(reg_ptr + 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t *const data, unsigned length) {
|
||||||
|
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||||
|
switch (offs & 0x3) {
|
||||||
|
case 0:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(reg_ptr + i) = *(data + i);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(reg_ptr + 1 + i) = *(data + i);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (auto i = 0U; i < length; ++i)
|
||||||
|
*(reg_ptr + 2 + i) = *(data + i);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*(reg_ptr + 3) = *data ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
* Copyright (C) 2019 - 2023 MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -99,6 +99,8 @@ public:
|
|||||||
|
|
||||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||||
|
using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t *const);
|
||||||
|
using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const *const);
|
||||||
|
|
||||||
// primary template
|
// primary template
|
||||||
template <class T, class Enable = void> struct hart_state {};
|
template <class T, class Enable = void> struct hart_state {};
|
||||||
@ -170,17 +172,94 @@ public:
|
|||||||
return 0b00000000000000000001100010001000;
|
return 0b00000000000000000001100010001000;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// specialization 64bit
|
||||||
|
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint64_t>::value>::type> {
|
||||||
|
public:
|
||||||
|
BEGIN_BF_DECL(mstatus_t, T);
|
||||||
|
// SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11)))
|
||||||
|
BF_FIELD(SD, 63, 1);
|
||||||
|
// value of XLEN for S-mode
|
||||||
|
BF_FIELD(SXL, 34, 2);
|
||||||
|
// value of XLEN for U-mode
|
||||||
|
BF_FIELD(UXL, 32, 2);
|
||||||
|
// Trap SRET
|
||||||
|
BF_FIELD(TSR, 22, 1);
|
||||||
|
// Timeout Wait
|
||||||
|
BF_FIELD(TW, 21, 1);
|
||||||
|
// Trap Virtual Memory
|
||||||
|
BF_FIELD(TVM, 20, 1);
|
||||||
|
// Make eXecutable Readable
|
||||||
|
BF_FIELD(MXR, 19, 1);
|
||||||
|
// permit Supervisor User Memory access
|
||||||
|
BF_FIELD(SUM, 18, 1);
|
||||||
|
// Modify PRiVilege
|
||||||
|
BF_FIELD(MPRV, 17, 1);
|
||||||
|
// status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
|
||||||
|
BF_FIELD(XS, 15, 2);
|
||||||
|
// floating-point unit status Off/Initial/Clean/Dirty
|
||||||
|
BF_FIELD(FS, 13, 2);
|
||||||
|
// machine previous privilege
|
||||||
|
BF_FIELD(MPP, 11, 2);
|
||||||
|
// supervisor previous privilege
|
||||||
|
BF_FIELD(SPP, 8, 1);
|
||||||
|
// previous machine interrupt-enable
|
||||||
|
BF_FIELD(MPIE, 7, 1);
|
||||||
|
// previous supervisor interrupt-enable
|
||||||
|
BF_FIELD(SPIE, 5, 1);
|
||||||
|
// previous user interrupt-enable
|
||||||
|
BF_FIELD(UPIE, 4, 1);
|
||||||
|
// machine interrupt-enable
|
||||||
|
BF_FIELD(MIE, 3, 1);
|
||||||
|
// supervisor interrupt-enable
|
||||||
|
BF_FIELD(SIE, 1, 1);
|
||||||
|
// user interrupt-enable
|
||||||
|
BF_FIELD(UIE, 0, 1);
|
||||||
|
END_BF_DECL();
|
||||||
|
|
||||||
|
mstatus_t mstatus;
|
||||||
|
|
||||||
|
static const reg_t mstatus_reset_val = 0x1800;
|
||||||
|
|
||||||
|
void write_mstatus(T val) {
|
||||||
|
auto mask = get_mask() &0xff; // MPP is hardcode as 0x3
|
||||||
|
auto new_val = (mstatus.backing.val & ~mask) | (val & mask);
|
||||||
|
mstatus = new_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr T get_mask() {
|
||||||
|
//return 0x8000000f007ff9ddULL; // 0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011
|
||||||
|
//
|
||||||
|
// +-TSR
|
||||||
|
// |+-TW
|
||||||
|
// ||+-TVM
|
||||||
|
// |||+-MXR
|
||||||
|
// ||||+-SUM
|
||||||
|
// |||||+-MPRV
|
||||||
|
// |||||| +-XS
|
||||||
|
// |||||| | +-FS
|
||||||
|
// |||||| | | +-MPP
|
||||||
|
// |||||| | | | +-SPP
|
||||||
|
// |||||| | | | |+-MPIE
|
||||||
|
// ||||||/|/|/| || +-MIE
|
||||||
|
return 0b00000000000000000001100010001000;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using hart_state_type = hart_state<reg_t>;
|
using hart_state_type = hart_state<reg_t>;
|
||||||
|
|
||||||
constexpr reg_t get_irq_mask() {
|
constexpr reg_t get_irq_mask() {
|
||||||
return 0b100010001000; // only machine mode is supported
|
return 0b100010001000; // only machine mode is supported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool has_compressed() {
|
||||||
|
return traits<BASE>::MISA_VAL&0b0100;
|
||||||
|
}
|
||||||
constexpr reg_t get_pc_mask() {
|
constexpr reg_t get_pc_mask() {
|
||||||
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
|
return has_compressed()?(reg_t)~1:(reg_t)~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_hart_m_p();
|
riscv_hart_m_p(feature_config cfg = feature_config{});
|
||||||
virtual ~riscv_hart_m_p() = default;
|
virtual ~riscv_hart_m_p() = default;
|
||||||
|
|
||||||
void reset(uint64_t address) override;
|
void reset(uint64_t address) override;
|
||||||
@ -192,28 +271,20 @@ public:
|
|||||||
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
||||||
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
||||||
|
|
||||||
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
|
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
|
||||||
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
||||||
virtual uint64_t leave_trap(uint64_t flags) override;
|
uint64_t leave_trap(uint64_t flags) override;
|
||||||
|
|
||||||
const reg_t& get_mhartid() const { return mhartid_reg; }
|
const reg_t& get_mhartid() const { return mhartid_reg; }
|
||||||
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
|
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
|
||||||
pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
pc, instr, (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
|
|
||||||
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
|
|
||||||
mem_read_cb = memReadCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
|
|
||||||
mem_write_cb = memWriteCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_csr(unsigned addr, reg_t val){
|
void set_csr(unsigned addr, reg_t val){
|
||||||
csr[addr & csr.page_addr_mask] = val;
|
csr[addr & csr.page_addr_mask] = val;
|
||||||
}
|
}
|
||||||
@ -233,22 +304,26 @@ protected:
|
|||||||
*/
|
*/
|
||||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||||
|
|
||||||
uint64_t get_pc() override { return arch.get_pc(); };
|
uint64_t get_pc() override { return arch.reg.PC; };
|
||||||
|
|
||||||
uint64_t get_next_pc() override { return arch.get_next_pc(); };
|
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||||
|
|
||||||
uint64_t get_instr_count() { return arch.reg.icount; }
|
uint64_t get_instr_word() override { return arch.instruction; }
|
||||||
|
|
||||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
uint64_t get_instr_count() override { return arch.icount; }
|
||||||
|
|
||||||
void set_curr_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||||
|
|
||||||
|
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
|
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||||
|
|
||||||
|
bool is_branch_taken() override { return arch.last_branch; };
|
||||||
|
|
||||||
riscv_hart_m_p<BASE, FEAT> &arch;
|
riscv_hart_m_p<BASE, FEAT> &arch;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend struct riscv_instrumentation_if;
|
friend struct riscv_instrumentation_if;
|
||||||
addr_t get_pc() { return this->reg.PC; }
|
|
||||||
addr_t get_next_pc() { return this->reg.NEXT_PC; }
|
|
||||||
|
|
||||||
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
|
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
|
||||||
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
|
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
|
||||||
@ -281,7 +356,6 @@ protected:
|
|||||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||||
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
|
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
|
||||||
uint8_t clic_cfg_reg{0};
|
uint8_t clic_cfg_reg{0};
|
||||||
uint32_t clic_info_reg{0};
|
|
||||||
std::array<uint32_t, 32> clic_inttrig_reg;
|
std::array<uint32_t, 32> clic_inttrig_reg;
|
||||||
union clic_int_reg_t {
|
union clic_int_reg_t {
|
||||||
struct{
|
struct{
|
||||||
@ -293,6 +367,10 @@ protected:
|
|||||||
uint32_t raw;
|
uint32_t raw;
|
||||||
};
|
};
|
||||||
std::vector<clic_int_reg_t> clic_int_reg;
|
std::vector<clic_int_reg_t> clic_int_reg;
|
||||||
|
uint8_t clic_mprev_lvl{0};
|
||||||
|
uint8_t clic_mact_lvl{0};
|
||||||
|
|
||||||
|
std::vector<uint8_t> tcm;
|
||||||
|
|
||||||
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
||||||
iss::status write_csr_reg(unsigned addr, reg_t val);
|
iss::status write_csr_reg(unsigned addr, reg_t val);
|
||||||
@ -306,51 +384,71 @@ protected:
|
|||||||
iss::status read_time(unsigned addr, reg_t &val);
|
iss::status read_time(unsigned addr, reg_t &val);
|
||||||
iss::status read_status(unsigned addr, reg_t &val);
|
iss::status read_status(unsigned addr, reg_t &val);
|
||||||
iss::status write_status(unsigned addr, reg_t val);
|
iss::status write_status(unsigned addr, reg_t val);
|
||||||
|
iss::status read_cause(unsigned addr, reg_t &val);
|
||||||
iss::status write_cause(unsigned addr, reg_t val);
|
iss::status write_cause(unsigned addr, reg_t val);
|
||||||
iss::status read_ie(unsigned addr, reg_t &val);
|
iss::status read_ie(unsigned addr, reg_t &val);
|
||||||
iss::status write_ie(unsigned addr, reg_t val);
|
iss::status write_ie(unsigned addr, reg_t val);
|
||||||
iss::status read_ip(unsigned addr, reg_t &val);
|
iss::status read_ip(unsigned addr, reg_t &val);
|
||||||
iss::status write_ip(unsigned addr, reg_t val);
|
|
||||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||||
iss::status write_epc(unsigned addr, reg_t val);
|
iss::status write_epc(unsigned addr, reg_t val);
|
||||||
iss::status write_intstatus(unsigned addr, reg_t val);
|
iss::status read_intstatus(unsigned addr, reg_t& val);
|
||||||
iss::status write_intthresh(unsigned addr, reg_t val);
|
iss::status write_intthresh(unsigned addr, reg_t val);
|
||||||
|
iss::status write_xtvt(unsigned addr, reg_t val);
|
||||||
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
||||||
iss::status read_dcsr_reg(unsigned addr, reg_t &val);
|
iss::status read_dcsr_reg(unsigned addr, reg_t &val);
|
||||||
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
||||||
iss::status read_dpc_reg(unsigned addr, reg_t &val);
|
iss::status read_dpc_reg(unsigned addr, reg_t &val);
|
||||||
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
||||||
|
|
||||||
|
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
|
||||||
|
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
|
||||||
|
|
||||||
|
void register_custom_csr_rd(unsigned addr){
|
||||||
|
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
|
||||||
|
}
|
||||||
|
void register_custom_csr_wr(unsigned addr){
|
||||||
|
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
|
||||||
|
}
|
||||||
|
|
||||||
reg_t mhartid_reg{0x0};
|
reg_t mhartid_reg{0x0};
|
||||||
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
|
|
||||||
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
|
|
||||||
|
|
||||||
void check_interrupt();
|
void check_interrupt();
|
||||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
||||||
uint64_t clic_base_addr{0};
|
std::vector<std::tuple<uint64_t, uint64_t>> memfn_range;
|
||||||
unsigned clic_num_irq{0};
|
std::vector<std::function<mem_read_f>> memfn_read;
|
||||||
unsigned clic_num_trigger{0};
|
std::vector<std::function<mem_write_f>> memfn_write;
|
||||||
unsigned mcause_max_irq{16};
|
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
|
||||||
|
feature_config cfg;
|
||||||
|
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
||||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
|
||||||
|
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
|
||||||
|
hart_mem_rd_delegate = rd;
|
||||||
|
hart_mem_wr_delegate = wr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::function<mem_read_f> hart_mem_rd_delegate;
|
||||||
|
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||||
: state()
|
: state()
|
||||||
, instr_if(*this) {
|
, instr_if(*this)
|
||||||
|
, cfg(cfg) {
|
||||||
// reset values
|
// reset values
|
||||||
csr[misa] = traits<BASE>::MISA_VAL;
|
csr[misa] = traits<BASE>::MISA_VAL;
|
||||||
csr[mvendorid] = 0x669;
|
csr[mvendorid] = 0x669;
|
||||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||||
csr[mimpid] = 1;
|
csr[mimpid] = 1;
|
||||||
csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file
|
|
||||||
|
|
||||||
uart_buf.str("");
|
uart_buf.str("");
|
||||||
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
|
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
|
||||||
csr_rd_cb[addr] = &this_class::read_null;
|
csr_rd_cb[addr] = &this_class::read_null;
|
||||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||||
}
|
}
|
||||||
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
if(traits<BASE>::XLEN==32) for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
|
||||||
csr_rd_cb[addr] = &this_class::read_null;
|
csr_rd_cb[addr] = &this_class::read_null;
|
||||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||||
}
|
}
|
||||||
@ -361,39 +459,45 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
|||||||
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
|
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
|
||||||
csr_rd_cb[addr] = &this_class::read_null;
|
csr_rd_cb[addr] = &this_class::read_null;
|
||||||
}
|
}
|
||||||
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
if(traits<BASE>::XLEN==32) for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
|
||||||
csr_rd_cb[addr] = &this_class::read_null;
|
csr_rd_cb[addr] = &this_class::read_null;
|
||||||
//csr_wr_cb[addr] = &this_class::write_csr_reg;
|
//csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||||
}
|
}
|
||||||
// common regs
|
// common regs
|
||||||
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
|
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
|
||||||
for(auto addr: addrs) {
|
for(auto addr: roaddrs) {
|
||||||
|
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||||
|
csr_wr_cb[addr] = &this_class::write_null;
|
||||||
|
}
|
||||||
|
const std::array<unsigned, 4> rwaddrs{{mepc, mtvec, mscratch, mtval}};
|
||||||
|
for(auto addr: rwaddrs) {
|
||||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||||
}
|
}
|
||||||
// special handling & overrides
|
// special handling & overrides
|
||||||
csr_rd_cb[time] = &this_class::read_time;
|
csr_rd_cb[time] = &this_class::read_time;
|
||||||
csr_rd_cb[timeh] = &this_class::read_time;
|
if(traits<BASE>::XLEN==32) csr_rd_cb[timeh] = &this_class::read_time;
|
||||||
csr_rd_cb[cycle] = &this_class::read_cycle;
|
csr_rd_cb[cycle] = &this_class::read_cycle;
|
||||||
csr_rd_cb[cycleh] = &this_class::read_cycle;
|
if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle;
|
||||||
csr_rd_cb[instret] = &this_class::read_instret;
|
csr_rd_cb[instret] = &this_class::read_instret;
|
||||||
csr_rd_cb[instreth] = &this_class::read_instret;
|
if(traits<BASE>::XLEN==32) csr_rd_cb[instreth] = &this_class::read_instret;
|
||||||
|
|
||||||
csr_rd_cb[mcycle] = &this_class::read_cycle;
|
csr_rd_cb[mcycle] = &this_class::read_cycle;
|
||||||
csr_wr_cb[mcycle] = &this_class::write_cycle;
|
csr_wr_cb[mcycle] = &this_class::write_cycle;
|
||||||
csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
||||||
csr_wr_cb[mcycleh] = &this_class::write_cycle;
|
if(traits<BASE>::XLEN==32) csr_wr_cb[mcycleh] = &this_class::write_cycle;
|
||||||
csr_rd_cb[minstret] = &this_class::read_instret;
|
csr_rd_cb[minstret] = &this_class::read_instret;
|
||||||
csr_wr_cb[minstret] = &this_class::write_instret;
|
csr_wr_cb[minstret] = &this_class::write_instret;
|
||||||
csr_rd_cb[minstreth] = &this_class::read_instret;
|
if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret;
|
||||||
csr_wr_cb[minstreth] = &this_class::write_instret;
|
if(traits<BASE>::XLEN==32) csr_wr_cb[minstreth] = &this_class::write_instret;
|
||||||
csr_rd_cb[mstatus] = &this_class::read_status;
|
csr_rd_cb[mstatus] = &this_class::read_status;
|
||||||
csr_wr_cb[mstatus] = &this_class::write_status;
|
csr_wr_cb[mstatus] = &this_class::write_status;
|
||||||
|
csr_rd_cb[mcause] = &this_class::read_cause;
|
||||||
csr_wr_cb[mcause] = &this_class::write_cause;
|
csr_wr_cb[mcause] = &this_class::write_cause;
|
||||||
csr_rd_cb[mtvec] = &this_class::read_tvec;
|
csr_rd_cb[mtvec] = &this_class::read_tvec;
|
||||||
csr_wr_cb[mepc] = &this_class::write_epc;
|
csr_wr_cb[mepc] = &this_class::write_epc;
|
||||||
csr_rd_cb[mip] = &this_class::read_ip;
|
csr_rd_cb[mip] = &this_class::read_ip;
|
||||||
csr_wr_cb[mip] = &this_class::write_ip;
|
csr_wr_cb[mip] = &this_class::write_null;
|
||||||
csr_rd_cb[mie] = &this_class::read_ie;
|
csr_rd_cb[mie] = &this_class::read_ie;
|
||||||
csr_wr_cb[mie] = &this_class::write_ie;
|
csr_wr_cb[mie] = &this_class::write_ie;
|
||||||
csr_rd_cb[mhartid] = &this_class::read_hartid;
|
csr_rd_cb[mhartid] = &this_class::read_hartid;
|
||||||
@ -401,6 +505,41 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
|||||||
csr_wr_cb[mvendorid] = &this_class::write_null;
|
csr_wr_cb[mvendorid] = &this_class::write_null;
|
||||||
csr_wr_cb[marchid] = &this_class::write_null;
|
csr_wr_cb[marchid] = &this_class::write_null;
|
||||||
csr_wr_cb[mimpid] = &this_class::write_null;
|
csr_wr_cb[mimpid] = &this_class::write_null;
|
||||||
|
if(FEAT & FEAT_CLIC) {
|
||||||
|
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
|
||||||
|
csr_wr_cb[mtvt] = &this_class::write_xtvt;
|
||||||
|
// csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||||
|
// csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||||
|
csr_rd_cb[mintstatus] = &this_class::read_intstatus;
|
||||||
|
csr_wr_cb[mintstatus] = &this_class::write_null;
|
||||||
|
// csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||||
|
// csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||||
|
// csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||||
|
// csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||||
|
csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
|
||||||
|
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
|
||||||
|
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw=0});
|
||||||
|
clic_cfg_reg=0x20;
|
||||||
|
clic_mact_lvl = clic_mprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||||
|
csr[mintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||||
|
insert_mem_range(cfg.clic_base, 0x5000UL,
|
||||||
|
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
|
||||||
|
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
|
||||||
|
}
|
||||||
|
if(FEAT & FEAT_TCM) {
|
||||||
|
tcm.resize(cfg.tcm_size);
|
||||||
|
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
|
||||||
|
auto offset=addr.val-this->cfg.tcm_base;
|
||||||
|
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
|
||||||
|
return iss::Ok;
|
||||||
|
};
|
||||||
|
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
|
||||||
|
auto offset=addr.val-this->cfg.tcm_base;
|
||||||
|
std::copy(data, data + length, tcm.data() + offset);
|
||||||
|
return iss::Ok;
|
||||||
|
};
|
||||||
|
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
|
||||||
|
}
|
||||||
if(FEAT & FEAT_DEBUG){
|
if(FEAT & FEAT_DEBUG){
|
||||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||||
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
||||||
@ -411,6 +550,12 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
|||||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
||||||
}
|
}
|
||||||
|
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status {
|
||||||
|
return this->read_mem(a, l, d);
|
||||||
|
};
|
||||||
|
hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status {
|
||||||
|
return this->write_mem(a, l, d);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
|
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||||
@ -418,10 +563,10 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
|||||||
if (fp) {
|
if (fp) {
|
||||||
std::array<char, 5> buf;
|
std::array<char, 5> buf;
|
||||||
auto n = fread(buf.data(), 1, 4, fp);
|
auto n = fread(buf.data(), 1, 4, fp);
|
||||||
|
fclose(fp);
|
||||||
if (n != 4) throw std::runtime_error("input file has insufficient size");
|
if (n != 4) throw std::runtime_error("input file has insufficient size");
|
||||||
buf[4] = 0;
|
buf[4] = 0;
|
||||||
if (strcmp(buf.data() + 1, "ELF") == 0) {
|
if (strcmp(buf.data() + 1, "ELF") == 0) {
|
||||||
fclose(fp);
|
|
||||||
// Create elfio reader
|
// Create elfio reader
|
||||||
ELFIO::elfio reader;
|
ELFIO::elfio reader;
|
||||||
// Load ELF data
|
// Load ELF data
|
||||||
@ -479,6 +624,20 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
|||||||
throw std::runtime_error("memory load file not found");
|
throw std::runtime_error("memory load file not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
inline void riscv_hart_m_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
|
||||||
|
std::function<mem_write_f> wr_fn) {
|
||||||
|
std::tuple<uint64_t, uint64_t> entry{base, size};
|
||||||
|
auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry,
|
||||||
|
[](std::tuple<uint64_t, uint64_t> const& a, std::tuple<uint64_t, uint64_t> const& b){
|
||||||
|
return std::get<0>(a)<std::get<0>(b);
|
||||||
|
});
|
||||||
|
auto idx = std::distance(memfn_range.begin(), it);
|
||||||
|
memfn_range.insert(it, entry);
|
||||||
|
memfn_read.insert(std::begin(memfn_read)+idx, rd_f);
|
||||||
|
memfn_write.insert(std::begin(memfn_write)+idx, wr_fn);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space,
|
iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space,
|
||||||
const uint64_t addr, const unsigned length, uint8_t *const data) {
|
const uint64_t addr, const unsigned length, uint8_t *const data) {
|
||||||
@ -494,29 +653,40 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
|||||||
try {
|
try {
|
||||||
switch (space) {
|
switch (space) {
|
||||||
case traits<BASE>::MEM: {
|
case traits<BASE>::MEM: {
|
||||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
auto alignment = is_fetch(access)? (has_compressed()? 2 : 4) : length;
|
||||||
|
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||||
fault_data = addr;
|
fault_data = addr;
|
||||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
if (is_debug(access)) throw trap_access(0, addr);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->trap_state = (1UL << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
if(!is_debug(access) && (addr&(alignment-1))){
|
||||||
if(alignment>1 && (addr&(alignment-1))){
|
this->trap_state = (1UL << 31) | 4<<16;
|
||||||
this->reg.trap_state = 1<<31 | 4<<16;
|
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
auto res = type==iss::address_type::PHYSICAL?
|
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
auto res = iss::Err;
|
||||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
if(access != access_type::FETCH && memfn_range.size()){
|
||||||
|
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||||
|
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||||
|
});
|
||||||
|
if(it!=std::end(memfn_range)) {
|
||||||
|
auto idx = std::distance(std::begin(memfn_range), it);
|
||||||
|
res = memfn_read[idx](phys_addr, length, data);
|
||||||
|
} else
|
||||||
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
|
} else {
|
||||||
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
|
}
|
||||||
if (unlikely(res != iss::Ok)){
|
if (unlikely(res != iss::Ok)){
|
||||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1UL << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -542,7 +712,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
|||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1UL << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -580,25 +750,36 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
|||||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||||
fault_data = addr;
|
fault_data = addr;
|
||||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->trap_state = (1UL << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(!(access && iss::access_type::DEBUG) && length>1 && (addr&(length-1))){
|
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||||
this->reg.trap_state = 1<<31 | 6<<16;
|
this->trap_state = (1UL << 31) | 6<<16;
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
auto res = type==iss::address_type::PHYSICAL?
|
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
auto res = iss::Err;
|
||||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
if(access != access_type::FETCH && memfn_range.size()){
|
||||||
|
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||||
|
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||||
|
});
|
||||||
|
if(it!=std::end(memfn_range)) {
|
||||||
|
auto idx = std::distance(std::begin(memfn_range), it);
|
||||||
|
res = memfn_write[idx]( phys_addr, length, data);
|
||||||
|
} else
|
||||||
|
res = write_mem( phys_addr, length, data);
|
||||||
|
} else {
|
||||||
|
res = write_mem( phys_addr, length, data);
|
||||||
|
}
|
||||||
if (unlikely(res != iss::Ok)) {
|
if (unlikely(res != iss::Ok)) {
|
||||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1UL << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -658,7 +839,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
|||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1UL << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -704,11 +885,10 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||||
auto cycle_val = this->reg.icount + cycle_offset;
|
auto cycle_val = this->icount + cycle_offset;
|
||||||
if (addr == mcycle) {
|
if (addr == mcycle) {
|
||||||
val = static_cast<reg_t>(cycle_val);
|
val = static_cast<reg_t>(cycle_val);
|
||||||
} else if (addr == mcycleh) {
|
} else if (addr == mcycleh) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
|
||||||
val = static_cast<reg_t>(cycle_val >> 32);
|
val = static_cast<reg_t>(cycle_val >> 32);
|
||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
@ -716,8 +896,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if (addr == mcycleh)
|
|
||||||
return iss::Err;
|
|
||||||
mcycle_csr = static_cast<uint64_t>(val);
|
mcycle_csr = static_cast<uint64_t>(val);
|
||||||
} else {
|
} else {
|
||||||
if (addr == mcycle) {
|
if (addr == mcycle) {
|
||||||
@ -726,38 +904,35 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
||||||
if ((addr&0xff) == (minstret&0xff)) {
|
if ((addr&0xff) == (minstret&0xff)) {
|
||||||
val = static_cast<reg_t>(this->reg.instret);
|
val = static_cast<reg_t>(this->instret);
|
||||||
} else if ((addr&0xff) == (minstreth&0xff)) {
|
} else if ((addr&0xff) == (minstreth&0xff)) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
val = static_cast<reg_t>(this->instret >> 32);
|
||||||
val = static_cast<reg_t>(this->reg.instret >> 32);
|
|
||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if ((addr&0xff) == (minstreth&0xff))
|
this->instret = static_cast<uint64_t>(val);
|
||||||
return iss::Err;
|
|
||||||
this->reg.instret = static_cast<uint64_t>(val);
|
|
||||||
} else {
|
} else {
|
||||||
if ((addr&0xff) == (minstret&0xff)) {
|
if ((addr&0xff) == (minstret&0xff)) {
|
||||||
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
|
this->instret = (this->instret & 0xffffffff00000000) + val;
|
||||||
} else {
|
} else {
|
||||||
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
|
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->reg.instret--;
|
this->instret--;
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||||
if (addr == time) {
|
if (addr == time) {
|
||||||
val = static_cast<reg_t>(time_val);
|
val = static_cast<reg_t>(time_val);
|
||||||
} else if (addr == timeh) {
|
} else if (addr == timeh) {
|
||||||
@ -768,7 +943,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) {
|
||||||
val = csr[mtvec] & ~2;
|
val = FEAT & features_e::FEAT_CLIC? csr[addr] : csr[addr] & ~2;
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,8 +958,30 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
|
||||||
|
auto res = csr[addr];
|
||||||
|
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||||
|
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||||
|
val |= clic_mprev_lvl<<16;
|
||||||
|
val |= state.mstatus.MPIE<<27;
|
||||||
|
val |= state.mstatus.MPP<<28;
|
||||||
|
} else
|
||||||
|
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||||
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))| (mcause_max_irq-1));
|
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||||
|
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
|
||||||
|
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
|
||||||
|
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||||
|
clic_mprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
|
||||||
|
state.mstatus.MPIE=(val>>27)&0x1;
|
||||||
|
state.mstatus.MPP=(val>>28)&0x3;
|
||||||
|
} else {
|
||||||
|
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
|
||||||
|
csr[addr] = (val & mask) | (csr[addr] & ~mask);
|
||||||
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,14 +1009,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) {
|
|
||||||
auto mask = get_irq_mask();
|
|
||||||
mask &= 0xf; // only xSIP is writable
|
|
||||||
csr[mip] = (csr[mip] & ~mask) | (val & mask);
|
|
||||||
check_interrupt();
|
|
||||||
return iss::Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
|
||||||
csr[addr] = val & get_pc_mask();
|
csr[addr] = val & get_pc_mask();
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
@ -864,9 +1053,26 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
iss::status riscv_hart_m_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||||
|
val = (clic_mact_lvl&0xff) <<24;
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
iss::status riscv_hart_m_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
|
||||||
|
csr[addr]= (val &0xff) | (1<<(cfg.clic_int_ctl_bits)) - 1;
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
iss::status riscv_hart_m_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||||
|
csr[addr]= val & ~0x3fULL;
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||||
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||||
if (sizeof(reg_t) < length) return iss::Err;
|
if (sizeof(reg_t) < length) return iss::Err;
|
||||||
@ -878,7 +1084,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
|
|||||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
if (this->icount > 30000) data[3] |= 0x80;
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
for(auto offs=0U; offs<length; ++offs) {
|
for(auto offs=0U; offs<length; ++offs) {
|
||||||
@ -891,14 +1097,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
|
|||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
||||||
if(mem_write_cb) return mem_write_cb(paddr, length, data);
|
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x10013000: // UART0 base, TXFIFO reg
|
case 0x10013000: // UART0 base, TXFIFO reg
|
||||||
case 0x10023000: // UART1 base, TXFIFO reg
|
case 0x10023000: // UART1 base, TXFIFO reg
|
||||||
uart_buf << (char)data[0];
|
uart_buf << (char)data[0];
|
||||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||||
// '"<<uart_buf.str()<<"'";
|
|
||||||
std::cout << uart_buf.str();
|
std::cout << uart_buf.str();
|
||||||
uart_buf.str("");
|
uart_buf.str("");
|
||||||
}
|
}
|
||||||
@ -938,7 +1142,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
|||||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||||
<< "), stopping simulation";
|
<< "), stopping simulation";
|
||||||
}
|
}
|
||||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||||
this->interrupt_sim=hostvar;
|
this->interrupt_sim=hostvar;
|
||||||
break;
|
break;
|
||||||
//throw(iss::simulation_stopped(hostvar));
|
//throw(iss::simulation_stopped(hostvar));
|
||||||
@ -967,12 +1171,45 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||||
|
if(addr==cfg.clic_base) { // cliccfg
|
||||||
|
*data=clic_cfg_reg;
|
||||||
|
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||||
|
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||||
|
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||||
|
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||||
|
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||||
|
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||||
|
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||||
|
} else {
|
||||||
|
for(auto i = 0U; i<length; ++i) *(data+i)=0;
|
||||||
|
}
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE, features_e FEAT>
|
||||||
|
iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||||
|
if(addr==cfg.clic_base) { // cliccfg
|
||||||
|
clic_cfg_reg = (clic_cfg_reg&~0x1e) | (*data&0x1e);
|
||||||
|
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||||
|
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||||
|
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||||
|
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||||
|
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||||
|
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||||
|
clic_int_reg[offset].raw &= 0xf0c70101; // clicIntCtlBits->0xf0, clicintattr->0xc7, clicintie->0x1, clicintip->0x1
|
||||||
|
}
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
|
template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
|
||||||
BASE::reset(address);
|
BASE::reset(address);
|
||||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
|
template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
|
||||||
|
//TODO: Implement CLIC functionality
|
||||||
//auto ideleg = csr[mideleg];
|
//auto ideleg = csr[mideleg];
|
||||||
// Multiple simultaneous interrupts and traps at the same privilege level are
|
// Multiple simultaneous interrupts and traps at the same privilege level are
|
||||||
// handled in the following decreasing priority order:
|
// handled in the following decreasing priority order:
|
||||||
@ -980,8 +1217,8 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
|||||||
// any synchronous traps.
|
// any synchronous traps.
|
||||||
auto ena_irq = csr[mip] & csr[mie];
|
auto ena_irq = csr[mip] & csr[mie];
|
||||||
|
|
||||||
bool mie = state.mstatus.MIE;
|
bool mstatus_mie = state.mstatus.MIE;
|
||||||
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
|
auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie;
|
||||||
auto enabled_interrupts = m_enabled ? ena_irq : 0;
|
auto enabled_interrupts = m_enabled ? ena_irq : 0;
|
||||||
|
|
||||||
if (enabled_interrupts != 0) {
|
if (enabled_interrupts != 0) {
|
||||||
@ -990,16 +1227,17 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
|||||||
enabled_interrupts >>= 1;
|
enabled_interrupts >>= 1;
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
||||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||||
// calculate and write mcause val
|
// calculate and write mcause val
|
||||||
auto trap_id = bit_sub<0, 16>(flags);
|
auto const trap_id = bit_sub<0, 16>(flags);
|
||||||
auto cause = bit_sub<16, 15>(flags);
|
auto cause = bit_sub<16, 15>(flags);
|
||||||
// calculate effective privilege level
|
// calculate effective privilege level
|
||||||
|
unsigned new_priv = PRIV_M;
|
||||||
if (trap_id == 0) { // exception
|
if (trap_id == 0) { // exception
|
||||||
if (cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
|
if (cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
|
||||||
// store ret addr in xepc register
|
// store ret addr in xepc register
|
||||||
@ -1016,13 +1254,16 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
|||||||
csr[mtval] = static_cast<reg_t>(addr);
|
csr[mtval] = static_cast<reg_t>(addr);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
csr[mtval] = (instr & 0x3)==3?instr:instr&0xffff;
|
csr[mtval] = (!has_compressed() || (instr & 0x3)==3)?instr:instr&0xffff;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
//TODO: implement debug mode behavior
|
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||||
// csr[dpc] = addr;
|
this->reg.DPC = addr;
|
||||||
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||||
|
new_priv = this->reg.PRIV | PRIV_D;
|
||||||
|
} else {
|
||||||
csr[mtval] = addr;
|
csr[mtval] = addr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
case 6:
|
case 6:
|
||||||
@ -1034,7 +1275,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
|||||||
fault_data = 0;
|
fault_data = 0;
|
||||||
} else {
|
} else {
|
||||||
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
||||||
this->reg.pending_trap = 0;
|
this->pending_trap = 0;
|
||||||
}
|
}
|
||||||
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||||
// update mstatus
|
// update mstatus
|
||||||
@ -1049,14 +1290,22 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
|||||||
state.mstatus.MIE = false;
|
state.mstatus.MIE = false;
|
||||||
|
|
||||||
// get trap vector
|
// get trap vector
|
||||||
auto ivec = csr[mtvec];
|
auto xtvec = csr[mtvec];
|
||||||
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
|
// calculate adds// set NEXT_PC to trap addressess to jump to based on MODE
|
||||||
|
if((FEAT & features_e::FEAT_CLIC) && trap_id!=0 && (xtvec & 0x3UL)==3UL) {
|
||||||
|
reg_t data;
|
||||||
|
auto ret = read(address_type::LOGICAL, access_type::READ, 0, csr[mtvt], sizeof(reg_t), reinterpret_cast<uint8_t*>(&data));
|
||||||
|
if(ret == iss::Err)
|
||||||
|
return this->reg.PC;
|
||||||
|
this->reg.NEXT_PC = data;
|
||||||
|
} else {
|
||||||
// bits in mtvec
|
// bits in mtvec
|
||||||
this->reg.NEXT_PC = ivec & ~0x3UL;
|
this->reg.NEXT_PC = xtvec & ~0x3UL;
|
||||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
if ((xtvec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||||
|
}
|
||||||
// reset trap state
|
// reset trap state
|
||||||
this->reg.PRIV = PRIV_M;
|
this->reg.PRIV = new_priv;
|
||||||
this->reg.trap_state = 0;
|
this->trap_state = 0;
|
||||||
std::array<char, 32> buffer;
|
std::array<char, 32> buffer;
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
sprintf(buffer.data(), "0x%016llx", addr);
|
sprintf(buffer.data(), "0x%016llx", addr);
|
||||||
@ -1077,6 +1326,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::l
|
|||||||
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
|
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
|
||||||
CLOG(INFO, disass) << "Executing xRET";
|
CLOG(INFO, disass) << "Executing xRET";
|
||||||
check_interrupt();
|
check_interrupt();
|
||||||
|
this->trap_state = this->pending_trap;
|
||||||
return this->reg.NEXT_PC;
|
return this->reg.NEXT_PC;
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -307,19 +307,11 @@ public:
|
|||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount + cycle_offset);
|
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
|
|
||||||
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
|
|
||||||
mem_read_cb = memReadCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
|
|
||||||
mem_write_cb = memWriteCb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_csr(unsigned addr, reg_t val){
|
void set_csr(unsigned addr, reg_t val){
|
||||||
csr[addr & csr.page_addr_mask] = val;
|
csr[addr & csr.page_addr_mask] = val;
|
||||||
}
|
}
|
||||||
@ -340,11 +332,17 @@ protected:
|
|||||||
|
|
||||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||||
|
|
||||||
uint64_t get_instr_count() { return arch.reg.icount; }
|
uint64_t get_instr_word() override { return arch.instruction; }
|
||||||
|
|
||||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
uint64_t get_instr_count() { return arch.icount; }
|
||||||
|
|
||||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||||
|
|
||||||
|
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
|
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||||
|
|
||||||
|
bool is_branch_taken() override { return arch.last_branch; };
|
||||||
|
|
||||||
riscv_hart_msu_vp<BASE> &arch;
|
riscv_hart_msu_vp<BASE> &arch;
|
||||||
};
|
};
|
||||||
@ -400,7 +398,6 @@ private:
|
|||||||
iss::status read_ie(unsigned addr, reg_t &val);
|
iss::status read_ie(unsigned addr, reg_t &val);
|
||||||
iss::status write_ie(unsigned addr, reg_t val);
|
iss::status write_ie(unsigned addr, reg_t val);
|
||||||
iss::status read_ip(unsigned addr, reg_t &val);
|
iss::status read_ip(unsigned addr, reg_t &val);
|
||||||
iss::status write_ip(unsigned addr, reg_t val);
|
|
||||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||||
iss::status write_epc(unsigned addr, reg_t val);
|
iss::status write_epc(unsigned addr, reg_t val);
|
||||||
iss::status read_satp(unsigned addr, reg_t &val);
|
iss::status read_satp(unsigned addr, reg_t &val);
|
||||||
@ -408,9 +405,17 @@ private:
|
|||||||
iss::status read_fcsr(unsigned addr, reg_t &val);
|
iss::status read_fcsr(unsigned addr, reg_t &val);
|
||||||
iss::status write_fcsr(unsigned addr, reg_t val);
|
iss::status write_fcsr(unsigned addr, reg_t val);
|
||||||
|
|
||||||
|
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
|
||||||
|
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
|
||||||
|
|
||||||
|
void register_custom_csr_rd(unsigned addr){
|
||||||
|
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
|
||||||
|
}
|
||||||
|
void register_custom_csr_wr(unsigned addr){
|
||||||
|
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
|
||||||
|
}
|
||||||
|
|
||||||
reg_t mhartid_reg{0x0};
|
reg_t mhartid_reg{0x0};
|
||||||
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
|
|
||||||
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void check_interrupt();
|
void check_interrupt();
|
||||||
@ -489,11 +494,11 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
|||||||
csr_wr_cb[sepc] = &this_class::write_epc;
|
csr_wr_cb[sepc] = &this_class::write_epc;
|
||||||
csr_wr_cb[uepc] = &this_class::write_epc;
|
csr_wr_cb[uepc] = &this_class::write_epc;
|
||||||
csr_rd_cb[mip] = &this_class::read_ip;
|
csr_rd_cb[mip] = &this_class::read_ip;
|
||||||
csr_wr_cb[mip] = &this_class::write_ip;
|
csr_wr_cb[mip] = &this_class::write_null;
|
||||||
csr_rd_cb[sip] = &this_class::read_ip;
|
csr_rd_cb[sip] = &this_class::read_ip;
|
||||||
csr_wr_cb[sip] = &this_class::write_ip;
|
csr_wr_cb[sip] = &this_class::write_null;
|
||||||
csr_rd_cb[uip] = &this_class::read_ip;
|
csr_rd_cb[uip] = &this_class::read_ip;
|
||||||
csr_wr_cb[uip] = &this_class::write_ip;
|
csr_wr_cb[uip] = &this_class::write_null;
|
||||||
csr_rd_cb[mie] = &this_class::read_ie;
|
csr_rd_cb[mie] = &this_class::read_ie;
|
||||||
csr_wr_cb[mie] = &this_class::write_ie;
|
csr_wr_cb[mie] = &this_class::write_ie;
|
||||||
csr_rd_cb[sie] = &this_class::read_ie;
|
csr_rd_cb[sie] = &this_class::read_ie;
|
||||||
@ -598,13 +603,19 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
|||||||
try {
|
try {
|
||||||
switch (space) {
|
switch (space) {
|
||||||
case traits<BASE>::MEM: {
|
case traits<BASE>::MEM: {
|
||||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||||
|
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||||
fault_data = addr;
|
fault_data = addr;
|
||||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->trap_state = (1 << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
if(!is_debug(access) && (addr&(alignment-1))){
|
||||||
|
this->trap_state = 1<<31 | 4<<16;
|
||||||
|
fault_data=addr;
|
||||||
|
return iss::Err;
|
||||||
|
}
|
||||||
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
|
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
|
||||||
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
|
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
|
||||||
if (vm.levels != 0) { // VM is active
|
if (vm.levels != 0) { // VM is active
|
||||||
@ -620,12 +631,12 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
|||||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
||||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||||
if (unlikely(res != iss::Ok)){
|
if (unlikely(res != iss::Ok)){
|
||||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1 << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -641,7 +652,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
|||||||
case 3: { // SFENCE:VMA upper
|
case 3: { // SFENCE:VMA upper
|
||||||
auto tvm = state.mstatus.TVM;
|
auto tvm = state.mstatus.TVM;
|
||||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -662,7 +673,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
|||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1 << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -700,7 +711,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
|||||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||||
fault_data = addr;
|
fault_data = addr;
|
||||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->trap_state = (1 << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -719,12 +730,12 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
|||||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
write_mem(phys_addr_t{access, space, addr}, length, data):
|
||||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||||
if (unlikely(res != iss::Ok)) {
|
if (unlikely(res != iss::Ok)) {
|
||||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1 << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -773,7 +784,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
|||||||
ptw.clear();
|
ptw.clear();
|
||||||
auto tvm = state.mstatus.TVM;
|
auto tvm = state.mstatus.TVM;
|
||||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -789,7 +800,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
|||||||
}
|
}
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
this->reg.trap_state = (1 << 31) | ta.id;
|
this->trap_state = (1 << 31) | ta.id;
|
||||||
fault_data=ta.addr;
|
fault_data=ta.addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -834,8 +845,8 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
||||||
auto cycle_val = this->reg.icount + cycle_offset;
|
auto cycle_val = this->icount + cycle_offset;
|
||||||
if (addr == mcycle) {
|
if (addr == mcycle) {
|
||||||
val = static_cast<reg_t>(cycle_val);
|
val = static_cast<reg_t>(cycle_val);
|
||||||
} else if (addr == mcycleh) {
|
} else if (addr == mcycleh) {
|
||||||
@ -845,7 +856,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if (addr == mcycleh)
|
if (addr == mcycleh)
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
@ -857,11 +868,11 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
|
|||||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsigned addr, reg_t &val) {
|
||||||
if ((addr&0xff) == (minstret&0xff)) {
|
if ((addr&0xff) == (minstret&0xff)) {
|
||||||
val = static_cast<reg_t>(this->reg.instret);
|
val = static_cast<reg_t>(this->reg.instret);
|
||||||
} else if ((addr&0xff) == (minstreth&0xff)) {
|
} else if ((addr&0xff) == (minstreth&0xff)) {
|
||||||
@ -871,7 +882,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if ((addr&0xff) == (minstreth&0xff))
|
if ((addr&0xff) == (minstreth&0xff))
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
@ -887,8 +898,8 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) {
|
||||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||||
if (addr == time) {
|
if (addr == time) {
|
||||||
val = static_cast<reg_t>(time_val);
|
val = static_cast<reg_t>(time_val);
|
||||||
} else if (addr == timeh) {
|
} else if (addr == timeh) {
|
||||||
@ -898,7 +909,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
||||||
val = csr[addr] & ~2;
|
val = csr[addr] & ~2;
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
@ -949,15 +960,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_ip(unsigned a
|
|||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ip(unsigned addr, reg_t val) {
|
|
||||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
|
||||||
auto mask = get_irq_mask(req_priv_lvl);
|
|
||||||
mask &= ~(1 << 7); // MTIP is read only
|
|
||||||
csr[mip] = (csr[mip] & ~mask) | (val & mask);
|
|
||||||
check_interrupt();
|
|
||||||
return iss::Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned addr, reg_t val) {
|
||||||
csr[addr] = val & get_pc_mask();
|
csr[addr] = val & get_pc_mask();
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
@ -966,7 +968,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned
|
|||||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
|
||||||
reg_t tvm = state.mstatus.TVM;
|
reg_t tvm = state.mstatus.TVM;
|
||||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -977,7 +979,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned
|
|||||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) {
|
||||||
reg_t tvm = state.mstatus.TVM;
|
reg_t tvm = state.mstatus.TVM;
|
||||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
@ -1021,7 +1023,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigne
|
|||||||
|
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||||
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||||
if (sizeof(reg_t) < length) return iss::Err;
|
if (sizeof(reg_t) < length) return iss::Err;
|
||||||
@ -1033,7 +1034,7 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
|
|||||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
if (this->icount > 30000) data[3] |= 0x80;
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
for(auto offs=0U; offs<length; ++offs) {
|
for(auto offs=0U; offs<length; ++offs) {
|
||||||
@ -1046,7 +1047,6 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
|
|||||||
|
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
||||||
if(mem_write_cb) return mem_write_cb(paddr, length, data);
|
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x10013000: // UART0 base, TXFIFO reg
|
case 0x10013000: // UART0 base, TXFIFO reg
|
||||||
case 0x10023000: // UART1 base, TXFIFO reg
|
case 0x10023000: // UART1 base, TXFIFO reg
|
||||||
@ -1093,7 +1093,7 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
|
|||||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||||
<< "), stopping simulation";
|
<< "), stopping simulation";
|
||||||
}
|
}
|
||||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||||
this->interrupt_sim=hostvar;
|
this->interrupt_sim=hostvar;
|
||||||
break;
|
break;
|
||||||
//throw(iss::simulation_stopped(hostvar));
|
//throw(iss::simulation_stopped(hostvar));
|
||||||
@ -1162,7 +1162,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
|||||||
if (enabled_interrupts != 0) {
|
if (enabled_interrupts != 0) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
|
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
|
||||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1306,7 +1306,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
|||||||
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||||
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
|
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
|
||||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||||
this->reg.pending_trap = 0;
|
this->pending_trap = 0;
|
||||||
}
|
}
|
||||||
size_t adr = ucause | (new_priv << 8);
|
size_t adr = ucause | (new_priv << 8);
|
||||||
csr[adr] = (trap_id << 31) + cause;
|
csr[adr] = (trap_id << 31) + cause;
|
||||||
@ -1351,7 +1351,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
|||||||
<< lvl[cur_priv] << " to " << lvl[new_priv];
|
<< lvl[cur_priv] << " to " << lvl[new_priv];
|
||||||
// reset trap state
|
// reset trap state
|
||||||
this->reg.PRIV = new_priv;
|
this->reg.PRIV = new_priv;
|
||||||
this->reg.trap_state = 0;
|
this->trap_state = 0;
|
||||||
update_vm_info();
|
update_vm_info();
|
||||||
return this->reg.NEXT_PC;
|
return this->reg.NEXT_PC;
|
||||||
}
|
}
|
||||||
@ -1363,7 +1363,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f
|
|||||||
|
|
||||||
auto tsr = state.mstatus.TSR;
|
auto tsr = state.mstatus.TSR;
|
||||||
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
|
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
return this->reg.PC;
|
return this->reg.PC;
|
||||||
}
|
}
|
||||||
@ -1402,7 +1402,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::wait_until(uint64_t flags
|
|||||||
auto status = state.mstatus;
|
auto status = state.mstatus;
|
||||||
auto tw = status.TW;
|
auto tw = status.TW;
|
||||||
if (this->reg.PRIV == PRIV_S && tw != 0) {
|
if (this->reg.PRIV == PRIV_S && tw != 0) {
|
||||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
this->trap_state = (1 << 31) | (2 << 16);
|
||||||
this->fault_data = this->reg.PC;
|
this->fault_data = this->reg.PC;
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,9 @@
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include "tgc_c.h"
|
||||||
#include "util/ities.h"
|
#include "util/ities.h"
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <iss/arch/tgc_c.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -41,12 +41,10 @@ using namespace iss::arch;
|
|||||||
|
|
||||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
||||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
|
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, 43> 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;
|
constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||||
|
|
||||||
tgc_c::tgc_c() {
|
tgc_c::tgc_c() = default;
|
||||||
reg.icount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tgc_c::~tgc_c() = default;
|
tgc_c::~tgc_c() = default;
|
||||||
|
|
||||||
@ -57,8 +55,8 @@ void tgc_c::reset(uint64_t address) {
|
|||||||
reg.PC=address;
|
reg.PC=address;
|
||||||
reg.NEXT_PC=reg.PC;
|
reg.NEXT_PC=reg.PC;
|
||||||
reg.PRIV=0x3;
|
reg.PRIV=0x3;
|
||||||
reg.trap_state=0;
|
trap_state=0;
|
||||||
reg.icount=0;
|
icount=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
uint8_t *tgc_c::get_regs_base_ptr() {
|
@ -53,17 +53,12 @@ template <> struct traits<tgc_c> {
|
|||||||
static constexpr std::array<const char*, 36> reg_aliases{
|
static constexpr std::array<const char*, 36> reg_aliases{
|
||||||
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
|
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
|
||||||
|
|
||||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
|
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, PGMASK=0b111111111111, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
|
||||||
|
|
||||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||||
|
|
||||||
enum reg_e {
|
enum reg_e {
|
||||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS,
|
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
|
||||||
TRAP_STATE=NUM_REGS,
|
|
||||||
PENDING_TRAP,
|
|
||||||
ICOUNT,
|
|
||||||
CYCLE,
|
|
||||||
INSTRET
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using reg_t = uint32_t;
|
using reg_t = uint32_t;
|
||||||
@ -76,17 +71,17 @@ template <> struct traits<tgc_c> {
|
|||||||
|
|
||||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||||
|
|
||||||
static constexpr std::array<const uint32_t, 41> reg_bit_widths{
|
static constexpr std::array<const uint32_t, 43> reg_bit_widths{
|
||||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64}};
|
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64,32,32}};
|
||||||
|
|
||||||
static constexpr std::array<const uint32_t, 41> reg_byte_offsets{
|
static constexpr std::array<const uint32_t, 43> reg_byte_offsets{
|
||||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165}};
|
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}};
|
||||||
|
|
||||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||||
|
|
||||||
enum sreg_flag_e { FLAGS };
|
enum sreg_flag_e { FLAGS };
|
||||||
|
|
||||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
enum mem_type_e { MEM, FENCE, RES, CSR };
|
||||||
|
|
||||||
enum class opcode_e : unsigned short {
|
enum class opcode_e : unsigned short {
|
||||||
LUI = 0,
|
LUI = 0,
|
||||||
@ -129,56 +124,53 @@ template <> struct traits<tgc_c> {
|
|||||||
FENCE = 37,
|
FENCE = 37,
|
||||||
ECALL = 38,
|
ECALL = 38,
|
||||||
EBREAK = 39,
|
EBREAK = 39,
|
||||||
URET = 40,
|
MRET = 40,
|
||||||
SRET = 41,
|
WFI = 41,
|
||||||
MRET = 42,
|
CSRRW = 42,
|
||||||
WFI = 43,
|
CSRRS = 43,
|
||||||
DRET = 44,
|
CSRRC = 44,
|
||||||
CSRRW = 45,
|
CSRRWI = 45,
|
||||||
CSRRS = 46,
|
CSRRSI = 46,
|
||||||
CSRRC = 47,
|
CSRRCI = 47,
|
||||||
CSRRWI = 48,
|
FENCE_I = 48,
|
||||||
CSRRSI = 49,
|
MUL = 49,
|
||||||
CSRRCI = 50,
|
MULH = 50,
|
||||||
FENCE_I = 51,
|
MULHSU = 51,
|
||||||
MUL = 52,
|
MULHU = 52,
|
||||||
MULH = 53,
|
DIV = 53,
|
||||||
MULHSU = 54,
|
DIVU = 54,
|
||||||
MULHU = 55,
|
REM = 55,
|
||||||
DIV = 56,
|
REMU = 56,
|
||||||
DIVU = 57,
|
CADDI4SPN = 57,
|
||||||
REM = 58,
|
CLW = 58,
|
||||||
REMU = 59,
|
CSW = 59,
|
||||||
CADDI4SPN = 60,
|
CADDI = 60,
|
||||||
CLW = 61,
|
CNOP = 61,
|
||||||
CSW = 62,
|
CJAL = 62,
|
||||||
CADDI = 63,
|
CLI = 63,
|
||||||
CNOP = 64,
|
CLUI = 64,
|
||||||
CJAL = 65,
|
CADDI16SP = 65,
|
||||||
CLI = 66,
|
__reserved_clui = 66,
|
||||||
CLUI = 67,
|
CSRLI = 67,
|
||||||
CADDI16SP = 68,
|
CSRAI = 68,
|
||||||
__reserved_clui = 69,
|
CANDI = 69,
|
||||||
CSRLI = 70,
|
CSUB = 70,
|
||||||
CSRAI = 71,
|
CXOR = 71,
|
||||||
CANDI = 72,
|
COR = 72,
|
||||||
CSUB = 73,
|
CAND = 73,
|
||||||
CXOR = 74,
|
CJ = 74,
|
||||||
COR = 75,
|
CBEQZ = 75,
|
||||||
CAND = 76,
|
CBNEZ = 76,
|
||||||
CJ = 77,
|
CSLLI = 77,
|
||||||
CBEQZ = 78,
|
CLWSP = 78,
|
||||||
CBNEZ = 79,
|
CMV = 79,
|
||||||
CSLLI = 80,
|
CJR = 80,
|
||||||
CLWSP = 81,
|
__reserved_cmv = 81,
|
||||||
CMV = 82,
|
CADD = 82,
|
||||||
CJR = 83,
|
CJALR = 83,
|
||||||
__reserved_cmv = 84,
|
CEBREAK = 84,
|
||||||
CADD = 85,
|
CSWSP = 85,
|
||||||
CJALR = 86,
|
DII = 86,
|
||||||
CEBREAK = 87,
|
|
||||||
CSWSP = 88,
|
|
||||||
DII = 89,
|
|
||||||
MAX_OPCODE
|
MAX_OPCODE
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -197,7 +189,7 @@ struct tgc_c: public arch_if {
|
|||||||
|
|
||||||
uint8_t* get_regs_base_ptr() override;
|
uint8_t* get_regs_base_ptr() override;
|
||||||
|
|
||||||
inline uint64_t get_icount() { return reg.icount; }
|
inline uint64_t get_icount() { return icount; }
|
||||||
|
|
||||||
inline bool should_stop() { return interrupt_sim; }
|
inline bool should_stop() { return interrupt_sim; }
|
||||||
|
|
||||||
@ -215,7 +207,7 @@ struct tgc_c: public arch_if {
|
|||||||
|
|
||||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||||
|
|
||||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
inline uint32_t get_last_branch() { return last_branch; }
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -258,10 +250,18 @@ struct tgc_c: public arch_if {
|
|||||||
uint32_t DPC = 0;
|
uint32_t DPC = 0;
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
|
uint64_t cycle = 0;
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t last_branch;
|
uint32_t instruction = 0;
|
||||||
|
uint32_t last_branch = 0;
|
||||||
} reg;
|
} reg;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
|
uint64_t icount = 0;
|
||||||
|
uint64_t cycle = 0;
|
||||||
|
uint64_t instret = 0;
|
||||||
|
uint32_t instruction = 0;
|
||||||
|
uint32_t last_branch = 0;
|
||||||
std::array<address_type, 4> addr_mode;
|
std::array<address_type, 4> addr_mode;
|
||||||
|
|
||||||
uint64_t interrupt_sim=0;
|
uint64_t interrupt_sim=0;
|
175
src/iss/arch/tgc_c_decoder.cpp
Normal file
175
src/iss/arch/tgc_c_decoder.cpp
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#include "tgc_c.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace arch {
|
||||||
|
namespace {
|
||||||
|
// according to
|
||||||
|
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||||
|
#ifdef __GCC__
|
||||||
|
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
||||||
|
#elif __cplusplus < 201402L
|
||||||
|
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
||||||
|
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
||||||
|
#else
|
||||||
|
constexpr size_t bit_count(uint32_t u) {
|
||||||
|
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||||||
|
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using opcode_e = traits<tgc_c>::opcode_e;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* start opcode definitions
|
||||||
|
****************************************************************************/
|
||||||
|
struct instruction_desriptor {
|
||||||
|
size_t length;
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t mask;
|
||||||
|
opcode_e op;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<instruction_desriptor, 90> instr_descr = {{
|
||||||
|
/* entries are: size, valid value, valid mask, function ptr */
|
||||||
|
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, opcode_e::LUI},
|
||||||
|
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, opcode_e::AUIPC},
|
||||||
|
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, opcode_e::JAL},
|
||||||
|
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, opcode_e::JALR},
|
||||||
|
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, opcode_e::BEQ},
|
||||||
|
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, opcode_e::BNE},
|
||||||
|
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, opcode_e::BLT},
|
||||||
|
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, opcode_e::BGE},
|
||||||
|
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, opcode_e::BLTU},
|
||||||
|
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, opcode_e::BGEU},
|
||||||
|
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, opcode_e::LB},
|
||||||
|
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, opcode_e::LH},
|
||||||
|
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, opcode_e::LW},
|
||||||
|
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, opcode_e::LBU},
|
||||||
|
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, opcode_e::LHU},
|
||||||
|
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, opcode_e::SB},
|
||||||
|
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, opcode_e::SH},
|
||||||
|
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, opcode_e::SW},
|
||||||
|
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, opcode_e::ADDI},
|
||||||
|
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, opcode_e::SLTI},
|
||||||
|
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, opcode_e::SLTIU},
|
||||||
|
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, opcode_e::XORI},
|
||||||
|
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, opcode_e::ORI},
|
||||||
|
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, opcode_e::ANDI},
|
||||||
|
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, opcode_e::SLLI},
|
||||||
|
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRLI},
|
||||||
|
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRAI},
|
||||||
|
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::ADD},
|
||||||
|
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::SUB},
|
||||||
|
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::SLL},
|
||||||
|
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::SLT},
|
||||||
|
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::SLTU},
|
||||||
|
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::XOR},
|
||||||
|
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRL},
|
||||||
|
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRA},
|
||||||
|
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::OR},
|
||||||
|
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::AND},
|
||||||
|
{32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE},
|
||||||
|
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, opcode_e::ECALL},
|
||||||
|
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, opcode_e::EBREAK},
|
||||||
|
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::URET},
|
||||||
|
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::SRET},
|
||||||
|
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::MRET},
|
||||||
|
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, opcode_e::WFI},
|
||||||
|
{32, 0b01111011001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::DRET},
|
||||||
|
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRW},
|
||||||
|
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRS},
|
||||||
|
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRC},
|
||||||
|
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRWI},
|
||||||
|
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRSI},
|
||||||
|
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRCI},
|
||||||
|
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE_I},
|
||||||
|
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::MUL},
|
||||||
|
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::MULH},
|
||||||
|
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::MULHSU},
|
||||||
|
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::MULHU},
|
||||||
|
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::DIV},
|
||||||
|
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::DIVU},
|
||||||
|
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::REM},
|
||||||
|
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::REMU},
|
||||||
|
{16, 0b0000000000000000, 0b1110000000000011, opcode_e::CADDI4SPN},
|
||||||
|
{16, 0b0100000000000000, 0b1110000000000011, opcode_e::CLW},
|
||||||
|
{16, 0b1100000000000000, 0b1110000000000011, opcode_e::CSW},
|
||||||
|
{16, 0b0000000000000001, 0b1110000000000011, opcode_e::CADDI},
|
||||||
|
{16, 0b0000000000000001, 0b1110111110000011, opcode_e::CNOP},
|
||||||
|
{16, 0b0010000000000001, 0b1110000000000011, opcode_e::CJAL},
|
||||||
|
{16, 0b0100000000000001, 0b1110000000000011, opcode_e::CLI},
|
||||||
|
{16, 0b0110000000000001, 0b1110000000000011, opcode_e::CLUI},
|
||||||
|
{16, 0b0110000100000001, 0b1110111110000011, opcode_e::CADDI16SP},
|
||||||
|
{16, 0b0110000000000001, 0b1111000001111111, opcode_e::__reserved_clui},
|
||||||
|
{16, 0b1000000000000001, 0b1111110000000011, opcode_e::CSRLI},
|
||||||
|
{16, 0b1000010000000001, 0b1111110000000011, opcode_e::CSRAI},
|
||||||
|
{16, 0b1000100000000001, 0b1110110000000011, opcode_e::CANDI},
|
||||||
|
{16, 0b1000110000000001, 0b1111110001100011, opcode_e::CSUB},
|
||||||
|
{16, 0b1000110000100001, 0b1111110001100011, opcode_e::CXOR},
|
||||||
|
{16, 0b1000110001000001, 0b1111110001100011, opcode_e::COR},
|
||||||
|
{16, 0b1000110001100001, 0b1111110001100011, opcode_e::CAND},
|
||||||
|
{16, 0b1010000000000001, 0b1110000000000011, opcode_e::CJ},
|
||||||
|
{16, 0b1100000000000001, 0b1110000000000011, opcode_e::CBEQZ},
|
||||||
|
{16, 0b1110000000000001, 0b1110000000000011, opcode_e::CBNEZ},
|
||||||
|
{16, 0b0000000000000010, 0b1111000000000011, opcode_e::CSLLI},
|
||||||
|
{16, 0b0100000000000010, 0b1110000000000011, opcode_e::CLWSP},
|
||||||
|
{16, 0b1000000000000010, 0b1111000000000011, opcode_e::CMV},
|
||||||
|
{16, 0b1000000000000010, 0b1111000001111111, opcode_e::CJR},
|
||||||
|
{16, 0b1000000000000010, 0b1111111111111111, opcode_e::__reserved_cmv},
|
||||||
|
{16, 0b1001000000000010, 0b1111000000000011, opcode_e::CADD},
|
||||||
|
{16, 0b1001000000000010, 0b1111000001111111, opcode_e::CJALR},
|
||||||
|
{16, 0b1001000000000010, 0b1111111111111111, opcode_e::CEBREAK},
|
||||||
|
{16, 0b1100000000000010, 0b1110000000000011, opcode_e::CSWSP},
|
||||||
|
{16, 0b0000000000000000, 0b1111111111111111, opcode_e::DII},
|
||||||
|
}};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct instruction_decoder<tgc_c> {
|
||||||
|
using opcode_e = traits<tgc_c>::opcode_e;
|
||||||
|
using code_word_t=traits<tgc_c>::code_word_t;
|
||||||
|
|
||||||
|
struct instruction_pattern {
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t mask;
|
||||||
|
opcode_e id;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
unsigned decode_instruction(T);
|
||||||
|
|
||||||
|
instruction_decoder() {
|
||||||
|
for (auto instr : instr_descr) {
|
||||||
|
auto quadrant = instr.value & 0x3;
|
||||||
|
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
||||||
|
}
|
||||||
|
for(auto& lut: qlut){
|
||||||
|
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
|
||||||
|
return bit_count(a.mask) > bit_count(b.mask);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned instruction_decoder<tgc_c>::decode_instruction<traits<tgc_c>::code_word_t>(traits<tgc_c>::code_word_t instr){
|
||||||
|
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
||||||
|
return !((instr&e.mask) ^ e.value );
|
||||||
|
});
|
||||||
|
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<instruction_decoder<tgc_c>> traits<tgc_c>::get_decoder(){
|
||||||
|
return std::make_unique<instruction_decoder<tgc_c>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
src/iss/arch/tgc_mapper.h
Normal file
50
src/iss/arch/tgc_mapper.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef _ISS_ARCH_TGC_MAPPER_H
|
||||||
|
#define _ISS_ARCH_TGC_MAPPER_H
|
||||||
|
|
||||||
|
#include "riscv_hart_m_p.h"
|
||||||
|
#include "tgc_c.h"
|
||||||
|
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||||
|
#ifdef CORE_TGC_A
|
||||||
|
#include "riscv_hart_m_p.h"
|
||||||
|
#include <iss/arch/tgc_a.h>
|
||||||
|
using tgc_a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_a>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_B
|
||||||
|
#include "riscv_hart_m_p.h"
|
||||||
|
#include <iss/arch/tgc_b.h>
|
||||||
|
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_C_XRB_NN
|
||||||
|
#include "riscv_hart_m_p.h"
|
||||||
|
#include "hwl.h"
|
||||||
|
#include <iss/arch/tgc_c_xrb_nn.h>
|
||||||
|
using tgc_c_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_D
|
||||||
|
#include "riscv_hart_mu_p.h"
|
||||||
|
#include <iss/arch/tgc_d.h>
|
||||||
|
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_D_XRB_MAC
|
||||||
|
#include "riscv_hart_mu_p.h"
|
||||||
|
#include <iss/arch/tgc_d_xrb_mac.h>
|
||||||
|
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_D_XRB_NN
|
||||||
|
#include "riscv_hart_mu_p.h"
|
||||||
|
#include "hwl.h"
|
||||||
|
#include <iss/arch/tgc_d_xrb_nn.h>
|
||||||
|
using tgc_d_xrb_nn_plat_type = iss::arch::hwl<iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_E
|
||||||
|
#include "riscv_hart_mu_p.h"
|
||||||
|
#include <iss/arch/tgc_e.h>
|
||||||
|
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_TGC_X
|
||||||
|
#include "riscv_hart_mu_p.h"
|
||||||
|
#include <iss/arch/tgc_x.h>
|
||||||
|
using tgc_x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
172
src/iss/arch/wt_cache.h
Normal file
172
src/iss/arch/wt_cache.h
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2023 MINRES Technologies GmbH
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* eyck@minres.com - initial implementation
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _RISCV_HART_M_P_WT_CACHE_H
|
||||||
|
#define _RISCV_HART_M_P_WT_CACHE_H
|
||||||
|
|
||||||
|
#include <iss/vm_types.h>
|
||||||
|
#include <util/ities.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace arch {
|
||||||
|
namespace cache {
|
||||||
|
|
||||||
|
enum class state { INVALID, VALID};
|
||||||
|
struct line {
|
||||||
|
uint64_t tag_addr{0};
|
||||||
|
state st{state::INVALID};
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
line(unsigned line_sz): data(line_sz) {}
|
||||||
|
};
|
||||||
|
struct set {
|
||||||
|
std::vector<line> ways;
|
||||||
|
set(unsigned ways_count, line const& l): ways(ways_count, l) {}
|
||||||
|
};
|
||||||
|
struct cache {
|
||||||
|
std::vector<set> sets;
|
||||||
|
|
||||||
|
cache(unsigned size, unsigned line_sz, unsigned ways) {
|
||||||
|
line const ref_line{line_sz};
|
||||||
|
set const ref_set{ways, ref_line};
|
||||||
|
sets.resize(size/(ways*line_sz), ref_set);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wt_policy {
|
||||||
|
bool is_cacheline_hit(cache& c );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// write thru, allocate on read, direct mapped or set-associative with round-robin replacement policy
|
||||||
|
template <typename BASE> class wt_cache : public BASE {
|
||||||
|
public:
|
||||||
|
using base_class = BASE;
|
||||||
|
using this_class = wt_cache<BASE>;
|
||||||
|
using reg_t = typename BASE::reg_t;
|
||||||
|
using mem_read_f = typename BASE::mem_read_f;
|
||||||
|
using mem_write_f = typename BASE::mem_write_f;
|
||||||
|
using phys_addr_t = typename BASE::phys_addr_t;
|
||||||
|
|
||||||
|
wt_cache();
|
||||||
|
virtual ~wt_cache() = default;
|
||||||
|
|
||||||
|
unsigned size{4096};
|
||||||
|
unsigned line_sz{32};
|
||||||
|
unsigned ways{1};
|
||||||
|
uint64_t io_address{0xf0000000};
|
||||||
|
uint64_t io_addr_mask{0xf0000000};
|
||||||
|
protected:
|
||||||
|
iss::status read_cache(phys_addr_t addr, unsigned, uint8_t *const);
|
||||||
|
iss::status write_cache(phys_addr_t addr, unsigned, uint8_t const *const);
|
||||||
|
std::function<mem_read_f> cache_mem_rd_delegate;
|
||||||
|
std::function<mem_write_f> cache_mem_wr_delegate;
|
||||||
|
std::unique_ptr<cache::cache> dcache_ptr;
|
||||||
|
std::unique_ptr<cache::cache> icache_ptr;
|
||||||
|
size_t get_way_select() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline wt_cache<BASE>::wt_cache() {
|
||||||
|
auto cb = base_class::replace_mem_access(
|
||||||
|
[this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return read_cache(a, l,d);},
|
||||||
|
[this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return write_cache(a, l,d);});
|
||||||
|
cache_mem_rd_delegate = cb.first;
|
||||||
|
cache_mem_wr_delegate = cb.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
iss::status iss::arch::wt_cache<BASE>::read_cache(phys_addr_t a, unsigned l, uint8_t* const d) {
|
||||||
|
if(!icache_ptr) {
|
||||||
|
icache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||||
|
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||||
|
}
|
||||||
|
if((a.val&io_addr_mask) != io_address) {
|
||||||
|
auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways);
|
||||||
|
auto tag_addr=a.val>>util::ilog2(line_sz);
|
||||||
|
auto& set = (is_fetch(a.access)?icache_ptr:dcache_ptr)->sets[set_addr];
|
||||||
|
for(auto& cl: set.ways) {
|
||||||
|
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
|
||||||
|
auto start_addr = a.val&(line_sz-1);
|
||||||
|
for(auto i = 0U; i<l; ++i)
|
||||||
|
d[i] = cl.data[start_addr+i];
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto& cl = set.ways[get_way_select()];
|
||||||
|
phys_addr_t cl_addr{a};
|
||||||
|
cl_addr.val=tag_addr<<util::ilog2(line_sz);
|
||||||
|
cache_mem_rd_delegate(cl_addr, line_sz, cl.data.data());
|
||||||
|
cl.tag_addr=tag_addr;
|
||||||
|
cl.st=cache::state::VALID;
|
||||||
|
auto start_addr = a.val&(line_sz-1);
|
||||||
|
for(auto i = 0U; i<l; ++i)
|
||||||
|
d[i] = cl.data[start_addr+i];
|
||||||
|
return iss::Ok;
|
||||||
|
} else
|
||||||
|
return cache_mem_rd_delegate(a, l, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
iss::status iss::arch::wt_cache<BASE>::write_cache(phys_addr_t a, unsigned l, const uint8_t* const d) {
|
||||||
|
if(!dcache_ptr)
|
||||||
|
dcache_ptr.reset(new cache::cache(size, line_sz, ways));
|
||||||
|
auto res = cache_mem_wr_delegate(a, l, d);
|
||||||
|
if(res == iss::Ok && ((a.val&io_addr_mask) != io_address)) {
|
||||||
|
auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways);
|
||||||
|
auto tag_addr=a.val>>util::ilog2(line_sz);
|
||||||
|
auto& set = dcache_ptr->sets[set_addr];
|
||||||
|
for(auto& cl: set.ways) {
|
||||||
|
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
|
||||||
|
auto start_addr = a.val&(line_sz-1);
|
||||||
|
for(auto i = 0U; i<l; ++i)
|
||||||
|
cl.data[start_addr+i] = d[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace arch
|
||||||
|
} // namespace iss
|
||||||
|
|
||||||
|
#endif /* _RISCV_HART_M_P_H */
|
@ -120,9 +120,9 @@ public:
|
|||||||
|
|
||||||
status packetsize_query(std::string &out_buf) override;
|
status packetsize_query(std::string &out_buf) override;
|
||||||
|
|
||||||
status add_break(int type, uint64_t addr, unsigned int length) override;
|
status add_break(break_type type, uint64_t addr, unsigned int length) override;
|
||||||
|
|
||||||
status remove_break(int type, uint64_t addr, unsigned int length) override;
|
status remove_break(break_type type, uint64_t addr, unsigned int length) override;
|
||||||
|
|
||||||
status resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
|
status resume_from_addr(bool step, int sig, uint64_t addr, rp_thread_ref thread,
|
||||||
std::function<void(unsigned)> stop_callback) override;
|
std::function<void(unsigned)> stop_callback) override;
|
||||||
@ -193,20 +193,20 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// work around fill with F type registers
|
// work around fill with F type registers
|
||||||
// if (arch::traits<ARCH>::NUM_REGS < 65) {
|
// if (arch::traits<ARCH>::NUM_REGS < 65) {
|
||||||
// auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
|
// auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
|
||||||
// for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
|
// for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
|
||||||
// for (size_t j = 0; j < reg_width; ++j) {
|
// for (size_t j = 0; j < reg_width; ++j) {
|
||||||
// data.push_back(0x0);
|
// data.push_back(0x0);
|
||||||
// avail.push_back(0x00);
|
// avail.push_back(0x00);
|
||||||
// }
|
// }
|
||||||
// // if(arch::traits<ARCH>::XLEN < 64)
|
// // if(arch::traits<ARCH>::XLEN < 64)
|
||||||
// // for(unsigned j=0; j<4; ++j){
|
// // for(unsigned j=0; j<4; ++j){
|
||||||
// // data.push_back(0x0);
|
// // data.push_back(0x0);
|
||||||
// // avail.push_back(0x00);
|
// // avail.push_back(0x00);
|
||||||
// // }
|
// // }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,13 +214,27 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
|
|||||||
auto start_reg=arch::traits<ARCH>::X0;
|
auto start_reg=arch::traits<ARCH>::X0;
|
||||||
auto *reg_base = core->get_regs_base_ptr();
|
auto *reg_base = core->get_regs_base_ptr();
|
||||||
auto iter = data.data();
|
auto iter = data.data();
|
||||||
|
bool e_ext = arch::traits<ARCH>::PC<32;
|
||||||
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||||
|
if(e_ext && reg_no>15){
|
||||||
|
if(reg_no==32){
|
||||||
|
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
|
||||||
|
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
|
||||||
|
std::copy(iter, iter + reg_width, reg_base);
|
||||||
|
} else {
|
||||||
|
const uint64_t zero_val=0;
|
||||||
|
auto reg_width = arch::traits<ARCH>::reg_bit_widths[15] / 8;
|
||||||
|
auto iter = (uint8_t*)&zero_val;
|
||||||
|
std::copy(iter, iter + reg_width, reg_base);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||||
std::copy(iter, iter + reg_width, reg_base);
|
std::copy(iter, iter + reg_width, reg_base);
|
||||||
iter += 4;
|
iter += 4;
|
||||||
reg_base += offset;
|
reg_base += offset;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +331,12 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::packetsize_query(std
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type, uint64_t addr, unsigned int length) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(break_type type, uint64_t addr, unsigned int length) {
|
||||||
|
switch(type) {
|
||||||
|
default:
|
||||||
|
return Err;
|
||||||
|
case SW_EXEC:
|
||||||
|
case HW_EXEC: {
|
||||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||||
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
||||||
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
||||||
@ -325,9 +344,16 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type,
|
|||||||
<< saddr.val << std::dec;
|
<< saddr.val << std::dec;
|
||||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||||
return Ok;
|
return Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int type, uint64_t addr, unsigned int length) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(break_type type, uint64_t addr, unsigned int length) {
|
||||||
|
switch(type) {
|
||||||
|
default:
|
||||||
|
return Err;
|
||||||
|
case SW_EXEC:
|
||||||
|
case HW_EXEC: {
|
||||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||||
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
||||||
if (handle) {
|
if (handle) {
|
||||||
@ -340,6 +366,8 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int typ
|
|||||||
}
|
}
|
||||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||||
return Err;
|
return Err;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
@ -50,7 +50,7 @@ std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_
|
|||||||
if(backend == "llvm")
|
if(backend == "llvm")
|
||||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_LLVM
|
#ifdef WITH_TCC
|
||||||
if(backend == "tcc")
|
if(backend == "tcc")
|
||||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||||
#endif
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,14 +32,14 @@
|
|||||||
* eyck@minres.com - initial API and implementation
|
* eyck@minres.com - initial API and implementation
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "iss/plugin/cycle_estimate.h"
|
#include "cycle_estimate.h"
|
||||||
|
|
||||||
#include <iss/arch_if.h>
|
#include <iss/arch_if.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/istreamwrapper.h>
|
#include <rapidjson/istreamwrapper.h>
|
||||||
#include "rapidjson/writer.h"
|
#include <rapidjson/writer.h>
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include <rapidjson/stringbuffer.h>
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
#include <rapidjson/error/en.h>
|
#include <rapidjson/error/en.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -48,7 +48,7 @@ using namespace rapidjson;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
||||||
: arch_instr(nullptr)
|
: instr_if(nullptr)
|
||||||
, config_file_name(config_file_name)
|
, config_file_name(config_file_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -57,9 +57,9 @@ iss::plugin::cycle_estimate::~cycle_estimate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
|
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
|
||||||
arch_instr = vm.get_arch()->get_instrumentation_if();
|
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||||
if(!arch_instr) return false;
|
if(!instr_if) return false;
|
||||||
const string core_name = arch_instr->core_type_name();
|
const string core_name = instr_if->core_type_name();
|
||||||
if (config_file_name.length() > 0) {
|
if (config_file_name.length() > 0) {
|
||||||
ifstream is(config_file_name);
|
ifstream is(config_file_name);
|
||||||
if (is.is_open()) {
|
if (is.is_open()) {
|
||||||
@ -107,12 +107,12 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
|
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
|
||||||
assert(arch_instr && "No instrumentation interface available but callback executed");
|
assert(instr_if && "No instrumentation interface available but callback executed");
|
||||||
auto entry = delays[instr_info.instr_id];
|
auto entry = delays[instr_info.instr_id];
|
||||||
bool taken = exc_info.branch_taken;
|
bool taken = instr_if->is_branch_taken();
|
||||||
if (exc_info.branch_taken && (entry.taken > 1))
|
if (taken && (entry.taken > 1))
|
||||||
arch_instr->set_curr_instr_cycles(entry.taken);
|
instr_if->update_last_instr_cycles(entry.taken);
|
||||||
else if (entry.not_taken > 1)
|
else if (entry.not_taken > 1)
|
||||||
arch_instr->set_curr_instr_cycles(entry.not_taken);
|
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -45,7 +45,7 @@ namespace iss {
|
|||||||
|
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
|
|
||||||
class cycle_estimate: public iss::vm_plugin {
|
class cycle_estimate: public vm_plugin {
|
||||||
BEGIN_BF_DECL(instr_desc, uint32_t)
|
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||||
BF_FIELD(taken, 24, 8)
|
BF_FIELD(taken, 24, 8)
|
||||||
BF_FIELD(not_taken, 16, 8)
|
BF_FIELD(not_taken, 16, 8)
|
||||||
@ -78,10 +78,10 @@ public:
|
|||||||
|
|
||||||
sync_type get_sync() override { return POST_SYNC; };
|
sync_type get_sync() override { return POST_SYNC; };
|
||||||
|
|
||||||
void callback(instr_info_t instr_info, exec_info const&) override;
|
void callback(instr_info_t instr_info) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iss::instrumentation_if *arch_instr;
|
iss::instrumentation_if *instr_if;
|
||||||
std::vector<instr_desc> delays;
|
std::vector<instr_desc> delays;
|
||||||
struct pair_hash {
|
struct pair_hash {
|
||||||
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
|
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023 MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,8 +32,8 @@
|
|||||||
* eyck@minres.com - initial API and implementation
|
* eyck@minres.com - initial API and implementation
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "iss/plugin/instruction_count.h"
|
#include "instruction_count.h"
|
||||||
#include "iss/instrumentation_if.h"
|
#include <iss/instrumentation_if.h>
|
||||||
|
|
||||||
#include <iss/arch_if.h>
|
#include <iss/arch_if.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
@ -90,6 +90,6 @@ bool iss::plugin::instruction_count::registration(const char* const version, vm_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
|
void iss::plugin::instruction_count::callback(instr_info_t instr_info) {
|
||||||
rep_counts[instr_info.instr_id]++;
|
rep_counts[instr_info.instr_id]++;
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -69,7 +69,7 @@ public:
|
|||||||
|
|
||||||
sync_type get_sync() override { return POST_SYNC; };
|
sync_type get_sync() override { return POST_SYNC; };
|
||||||
|
|
||||||
void callback(instr_info_t, exec_info const&) override;
|
void callback(instr_info_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Json::Value root;
|
Json::Value root;
|
214
src/iss/plugin/pctrace.cpp
Normal file
214
src/iss/plugin/pctrace.cpp
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* alex.com - initial implementation
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <iss/arch_if.h>
|
||||||
|
#include <iss/plugin/pctrace.h>
|
||||||
|
#include <util/logging.h>
|
||||||
|
#include <util/ities.h>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/istreamwrapper.h>
|
||||||
|
#include <rapidjson/writer.h>
|
||||||
|
#include <rapidjson/stringbuffer.h>
|
||||||
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#ifdef WITH_LZ4
|
||||||
|
#include <lz4frame.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace plugin {
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#ifdef WITH_LZ4
|
||||||
|
class lz4compress_steambuf: public std::streambuf {
|
||||||
|
public:
|
||||||
|
lz4compress_steambuf(const lz4compress_steambuf&) = delete;
|
||||||
|
lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
|
||||||
|
lz4compress_steambuf(std::ostream &sink, size_t buf_size)
|
||||||
|
: sink(sink)
|
||||||
|
, src_buf(buf_size)
|
||||||
|
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
|
||||||
|
{
|
||||||
|
auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
||||||
|
if (LZ4F_isError(errCode) != 0)
|
||||||
|
throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
|
||||||
|
size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr);
|
||||||
|
if (LZ4F_isError(ret) != 0)
|
||||||
|
throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||||
|
setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
|
||||||
|
sink.write(dest_buf.data(), ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
~lz4compress_steambuf() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
if (closed)
|
||||||
|
return;
|
||||||
|
sync();
|
||||||
|
auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
|
||||||
|
if (LZ4F_isError(ret) != 0)
|
||||||
|
throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||||
|
sink.write(dest_buf.data(), ret);
|
||||||
|
LZ4F_freeCompressionContext(ctx);
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int_type overflow(int_type ch) override {
|
||||||
|
compress_and_write();
|
||||||
|
*pptr() = static_cast<char_type>(ch);
|
||||||
|
pbump(1);
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_type sync() override {
|
||||||
|
compress_and_write();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compress_and_write() {
|
||||||
|
if (closed)
|
||||||
|
throw std::runtime_error("Cannot write to closed stream");
|
||||||
|
if(auto orig_size = pptr() - pbase()){
|
||||||
|
auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
|
||||||
|
if (LZ4F_isError(ret) != 0)
|
||||||
|
throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
|
||||||
|
if(ret) sink.write(dest_buf.data(), ret);
|
||||||
|
pbump(-orig_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &sink;
|
||||||
|
std::vector<char> src_buf;
|
||||||
|
std::vector<char> dest_buf;
|
||||||
|
LZ4F_compressionContext_t ctx{ nullptr };
|
||||||
|
bool closed{ false };
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pctrace::pctrace(std::string const &filename)
|
||||||
|
: instr_if(nullptr)
|
||||||
|
, filename(filename)
|
||||||
|
, output("output.trc")
|
||||||
|
#ifdef WITH_LZ4
|
||||||
|
, strbuf(new lz4compress_steambuf(output, 4096))
|
||||||
|
, ostr(strbuf.get())
|
||||||
|
#endif
|
||||||
|
{ }
|
||||||
|
|
||||||
|
pctrace::~pctrace() { }
|
||||||
|
|
||||||
|
bool pctrace::registration(const char *const version, vm_if& vm) {
|
||||||
|
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||||
|
if(!instr_if) return false;
|
||||||
|
const string core_name = instr_if->core_type_name();
|
||||||
|
if (filename.length() > 0) {
|
||||||
|
ifstream is(filename);
|
||||||
|
if (is.is_open()) {
|
||||||
|
try {
|
||||||
|
IStreamWrapper isw(is);
|
||||||
|
Document d;
|
||||||
|
ParseResult ok = d.ParseStream(isw);
|
||||||
|
if(ok) {
|
||||||
|
Value& val = d[core_name.c_str()];
|
||||||
|
if(val.IsArray()){
|
||||||
|
delays.reserve(val.Size());
|
||||||
|
for (auto it = val.Begin(); it != val.End(); ++it) {
|
||||||
|
auto& name = (*it)["name"];
|
||||||
|
auto& size = (*it)["size"];
|
||||||
|
auto& delay = (*it)["delay"];
|
||||||
|
auto& branch = (*it)["branch"];
|
||||||
|
if(delay.IsArray()) {
|
||||||
|
auto dt = delay[0].Get<unsigned>();
|
||||||
|
auto dnt = delay[1].Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
||||||
|
} else if(delay.Is<unsigned>()) {
|
||||||
|
auto d = delay.Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
||||||
|
} else
|
||||||
|
throw runtime_error("JSON parse error");
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (runtime_error &e) {
|
||||||
|
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERR) << "Could not open input file " << filename;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pctrace::callback(instr_info_t iinfo) {
|
||||||
|
auto delay = 0;
|
||||||
|
size_t id = iinfo.instr_id;
|
||||||
|
auto entry = delays[id];
|
||||||
|
auto instr = instr_if->get_instr_word();
|
||||||
|
auto call = id==65 || id ==86 || ((id==2 || id==3) && bit_sub<7,5>(instr)!=0) ;//not taking care of tail calls (jalr with loading x6)
|
||||||
|
bool taken = instr_if->is_branch_taken();
|
||||||
|
bool compressed = (instr&0x3)!=0x3;
|
||||||
|
if (taken) {
|
||||||
|
delay = entry.taken;
|
||||||
|
if(entry.taken > 1)
|
||||||
|
instr_if->update_last_instr_cycles(entry.taken);
|
||||||
|
} else {
|
||||||
|
delay = entry.not_taken;
|
||||||
|
if (entry.not_taken > 1)
|
||||||
|
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||||
|
}
|
||||||
|
#ifndef WITH_LZ4
|
||||||
|
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||||
|
#else
|
||||||
|
auto rdbuf=ostr.rdbuf();
|
||||||
|
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
* Copyright (C) 2017 - 2023, MINRES Technologies GmbH
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -44,8 +44,8 @@
|
|||||||
|
|
||||||
namespace iss {
|
namespace iss {
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
|
class lz4compress_steambuf;
|
||||||
class cov : public iss::vm_plugin {
|
class pctrace : public iss::vm_plugin {
|
||||||
struct instr_delay {
|
struct instr_delay {
|
||||||
std::string instr_name;
|
std::string instr_name;
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -67,31 +67,34 @@ class cov : public iss::vm_plugin {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cov(const cov &) = delete;
|
pctrace(const pctrace &) = delete;
|
||||||
|
|
||||||
cov(const cov &&) = delete;
|
pctrace(const pctrace &&) = delete;
|
||||||
|
|
||||||
cov(std::string const &);
|
pctrace(std::string const &);
|
||||||
|
|
||||||
virtual ~cov();
|
virtual ~pctrace();
|
||||||
|
|
||||||
cov &operator=(const cov &) = delete;
|
pctrace &operator=(const pctrace &) = delete;
|
||||||
|
|
||||||
cov &operator=(const cov &&) = delete;
|
pctrace &operator=(const pctrace &&) = delete;
|
||||||
|
|
||||||
bool registration(const char *const version, vm_if &arch) override;
|
bool registration(const char *const version, vm_if &arch) override;
|
||||||
|
|
||||||
sync_type get_sync() override { return POST_SYNC; };
|
sync_type get_sync() override { return POST_SYNC; };
|
||||||
|
|
||||||
void callback(instr_info_t, exec_info const&) override;
|
void callback(instr_info_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iss::instrumentation_if *instr_if {nullptr};
|
iss::instrumentation_if *instr_if {nullptr};
|
||||||
std::ofstream output;
|
std::ofstream output;
|
||||||
|
#ifdef WITH_LZ4
|
||||||
|
std::unique_ptr<lz4compress_steambuf> strbuf;
|
||||||
|
std::ostream ostr;
|
||||||
|
#endif
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::vector<instr_desc> delays;
|
std::vector<instr_desc> delays;
|
||||||
bool jumped, first;
|
bool jumped{false}, first{true};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
65
src/main.cpp
65
src/main.cpp
@ -31,51 +31,21 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iss/factory.h>
|
#include "iss/factory.h"
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <iss/arch/riscv_hart_m_p.h>
|
#include "iss/arch/tgc_mapper.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_C_XRB_NN
|
|
||||||
#include "iss/arch/riscv_hart_m_p.h"
|
|
||||||
#include "iss/arch/tgc_c_xrb_nn.h"
|
|
||||||
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
|
|
||||||
#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 CORE_TGC_D_XRB_NN
|
|
||||||
#include "iss/arch/riscv_hart_mu_p.h"
|
|
||||||
#include "iss/arch/tgc_d_xrb_nn.h"
|
|
||||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
|
||||||
#endif
|
|
||||||
#ifdef CORE_TGC_E
|
|
||||||
#include "iss/arch/riscv_hart_mu_p.h"
|
|
||||||
#include "iss/arch/tgc_e.h"
|
|
||||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_LLVM
|
#ifdef WITH_LLVM
|
||||||
#include <iss/llvm/jit_helper.h>
|
#include <iss/llvm/jit_helper.h>
|
||||||
#endif
|
#endif
|
||||||
#include <iss/log_categories.h>
|
#include <iss/log_categories.h>
|
||||||
#include <iss/plugin/cycle_estimate.h>
|
#include "iss/plugin/cycle_estimate.h"
|
||||||
#include <iss/plugin/instruction_count.h>
|
#include "iss/plugin/instruction_count.h"
|
||||||
|
#include "iss/plugin/pctrace.h"
|
||||||
|
#ifndef WIN32
|
||||||
#include <iss/plugin/loader.h>
|
#include <iss/plugin/loader.h>
|
||||||
|
#endif
|
||||||
#if defined(HAS_LUA)
|
#if defined(HAS_LUA)
|
||||||
#include <iss/plugin/lua.h>
|
#include <iss/plugin/lua.h>
|
||||||
#endif
|
#endif
|
||||||
@ -92,13 +62,13 @@ int main(int argc, char *argv[]) {
|
|||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "Print help message")
|
("help,h", "Print help message")
|
||||||
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
||||||
("logfile,f", po::value<std::string>(), "Sets default log file.")
|
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||||
("reset,r", po::value<std::string>(), "reset address")
|
("reset,r", po::value<std::string>(), "reset address")
|
||||||
("dump-ir", "dump the intermediate representation")
|
("dump-ir", "dump the intermediate representation")
|
||||||
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||||
("mem,m", po::value<std::string>(), "the memory input file")
|
("mem,m", po::value<std::string>(), "the memory input file")
|
||||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||||
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
||||||
@ -191,6 +161,14 @@ int main(int argc, char *argv[]) {
|
|||||||
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
|
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
|
||||||
return 127;
|
return 127;
|
||||||
}
|
}
|
||||||
|
if(!cpu ){
|
||||||
|
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
|
if(!vm ){
|
||||||
|
LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
if (clim.count("plugin")) {
|
if (clim.count("plugin")) {
|
||||||
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
|
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
|
||||||
std::string plugin_name=opt_val;
|
std::string plugin_name=opt_val;
|
||||||
@ -208,14 +186,21 @@ int main(int argc, char *argv[]) {
|
|||||||
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
|
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
|
||||||
vm->register_plugin(*ce_plugin);
|
vm->register_plugin(*ce_plugin);
|
||||||
plugin_list.push_back(ce_plugin);
|
plugin_list.push_back(ce_plugin);
|
||||||
|
} else if (plugin_name == "pctrace") {
|
||||||
|
auto *plugin = new iss::plugin::pctrace(filename);
|
||||||
|
vm->register_plugin(*plugin);
|
||||||
|
plugin_list.push_back(plugin);
|
||||||
} else {
|
} else {
|
||||||
|
#ifndef WIN32
|
||||||
std::array<char const*, 1> a{{filename.c_str()}};
|
std::array<char const*, 1> a{{filename.c_str()}};
|
||||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||||
if(plugin){
|
if(plugin){
|
||||||
vm->register_plugin(*plugin);
|
vm->register_plugin(*plugin);
|
||||||
plugin_list.push_back(plugin);
|
plugin_list.push_back(plugin);
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||||
return 127;
|
return 127;
|
||||||
}
|
}
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
#include <iss/arch_if.h>
|
|
||||||
#include <iss/plugin/pctrace.h>
|
|
||||||
#include <util/logging.h>
|
|
||||||
#include <rapidjson/document.h>
|
|
||||||
#include <rapidjson/istreamwrapper.h>
|
|
||||||
#include "rapidjson/writer.h"
|
|
||||||
#include "rapidjson/stringbuffer.h"
|
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
|
||||||
#include <rapidjson/error/en.h>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace rapidjson;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
iss::plugin::cov::cov(std::string const &filename)
|
|
||||||
: instr_if(nullptr)
|
|
||||||
, filename(filename)
|
|
||||||
{
|
|
||||||
output.open("output.trc");
|
|
||||||
jumped = false;
|
|
||||||
first = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
iss::plugin::cov::~cov() {
|
|
||||||
output.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
|
||||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
|
||||||
if(!instr_if) return false;
|
|
||||||
const string core_name = instr_if->core_type_name();
|
|
||||||
if (filename.length() > 0) {
|
|
||||||
ifstream is(filename);
|
|
||||||
if (is.is_open()) {
|
|
||||||
try {
|
|
||||||
IStreamWrapper isw(is);
|
|
||||||
Document d;
|
|
||||||
ParseResult ok = d.ParseStream(isw);
|
|
||||||
if(ok) {
|
|
||||||
Value& val = d[core_name.c_str()];
|
|
||||||
if(val.IsArray()){
|
|
||||||
delays.reserve(val.Size());
|
|
||||||
for (auto it = val.Begin(); it != val.End(); ++it) {
|
|
||||||
auto& name = (*it)["name"];
|
|
||||||
auto& size = (*it)["size"];
|
|
||||||
auto& delay = (*it)["delay"];
|
|
||||||
auto& branch = (*it)["branch"];
|
|
||||||
if(delay.IsArray()) {
|
|
||||||
auto dt = delay[0].Get<unsigned>();
|
|
||||||
auto dnt = delay[1].Get<unsigned>();
|
|
||||||
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
|
||||||
} else if(delay.Is<unsigned>()) {
|
|
||||||
auto d = delay.Get<unsigned>();
|
|
||||||
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
|
||||||
} else
|
|
||||||
throw runtime_error("JSON parse error");
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (runtime_error &e) {
|
|
||||||
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(ERR) << "Could not open input file " << filename;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string formatPC(uint64_t pc) {
|
|
||||||
stringstream stream;
|
|
||||||
stream << "0x" << std::hex << pc;
|
|
||||||
return stream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
|
||||||
// auto delay = 0;
|
|
||||||
// auto entry = delays[iinfo.instr_id];
|
|
||||||
// bool taken = einfo.branch_taken;
|
|
||||||
// if (einfo.branch_taken)
|
|
||||||
// delay = entry.taken;
|
|
||||||
// else
|
|
||||||
// delay = entry.not_taken;
|
|
||||||
//
|
|
||||||
// if (first){
|
|
||||||
// output << formatPC(instr_if->get_pc()) << "," << delay;
|
|
||||||
// first = false;
|
|
||||||
// }
|
|
||||||
// if(instr_if->get_next_pc()-instr_if->get_pc() != delays[iinfo.instr_id].size/8){
|
|
||||||
// //The goal is to keep the output in start-target pairs, so after a jump the target address needs to get written
|
|
||||||
// //to the output. If the target happens to also be a start, we keep the pairing by adding a 0-delay entry.
|
|
||||||
// if (jumped)
|
|
||||||
// output <<"\n" <<formatPC(instr_if->get_pc()) << "," << 0;
|
|
||||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
|
||||||
// jumped = true;
|
|
||||||
// }
|
|
||||||
// else{
|
|
||||||
// if (jumped){
|
|
||||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
|
||||||
// jumped = false;
|
|
||||||
// }
|
|
||||||
// else if(delay!=1){
|
|
||||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
|
||||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
//source code for the full output
|
|
||||||
auto delay = 0;
|
|
||||||
auto entry = delays[iinfo.instr_id];
|
|
||||||
bool taken = einfo.branch_taken;
|
|
||||||
if (einfo.branch_taken)
|
|
||||||
delay = entry.taken;
|
|
||||||
else
|
|
||||||
delay = entry.not_taken;
|
|
||||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
|
||||||
}
|
|
@ -31,37 +31,17 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include "iss/debugger/gdb_session.h"
|
#include <iss/debugger/gdb_session.h>
|
||||||
#include "iss/debugger/encoderdecoder.h"
|
#include <iss/debugger/encoderdecoder.h>
|
||||||
#include "iss/debugger/server.h"
|
#include <iss/debugger/server.h>
|
||||||
#include "iss/debugger/target_adapter_if.h"
|
#include <iss/debugger/target_adapter_if.h>
|
||||||
#include "iss/iss.h"
|
#include <iss/iss.h>
|
||||||
#include "iss/vm_types.h"
|
#include <iss/vm_types.h>
|
||||||
|
#ifndef WIN32
|
||||||
#include <iss/plugin/loader.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
|
|
||||||
#ifdef CORE_TGC_D_XRB_NN
|
|
||||||
#include "iss/arch/riscv_hart_mu_p.h"
|
|
||||||
#include "iss/arch/tgc_d_xrb_nn.h"
|
|
||||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, iss::arch::FEAT_PMP>;
|
|
||||||
#endif
|
#endif
|
||||||
|
#include "core_complex.h"
|
||||||
|
#include <iss/arch/tgc_mapper.h>
|
||||||
#include <scc/report.h>
|
#include <scc/report.h>
|
||||||
#include <util/ities.h>
|
#include <util/ities.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -127,7 +107,8 @@ public:
|
|||||||
heart_state_t &get_state() { return this->state; }
|
heart_state_t &get_state() { return this->state; }
|
||||||
|
|
||||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||||
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
|
if (p == iss::arch_if::ISTART)
|
||||||
|
owner->sync(this->instr_if.get_total_cycles());
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_type needed_sync() const override { return PRE_SYNC; }
|
sync_type needed_sync() const override { return PRE_SYNC; }
|
||||||
@ -137,7 +118,7 @@ public:
|
|||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
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:"
|
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
|
||||||
<< this->reg.icount + this->cycle_offset << "]";
|
<< this->icount + this->cycle_offset << "]";
|
||||||
SCCDEBUG(owner->name())<<"disass: "
|
SCCDEBUG(owner->name())<<"disass: "
|
||||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||||
<< std::setfill(' ') << std::left << instr << s.str();
|
<< std::setfill(' ') << std::left << instr << s.str();
|
||||||
@ -148,7 +129,7 @@ public:
|
|||||||
if (addr.access && access_type::DEBUG)
|
if (addr.access && access_type::DEBUG)
|
||||||
return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
|
return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
|
||||||
else {
|
else {
|
||||||
return owner->read_mem(addr.val, length, data, addr.access && access_type::FETCH) ? Ok : Err;
|
return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? Ok : Err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,26 +178,26 @@ public:
|
|||||||
|
|
||||||
void wait_until(uint64_t flags) override {
|
void wait_until(uint64_t flags) override {
|
||||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||||
do {
|
while(this->pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
|
||||||
sc_core::wait(wfi_evt);
|
sc_core::wait(wfi_evt);
|
||||||
} while (this->reg.pending_trap == 0);
|
}
|
||||||
PLAT::wait_until(flags);
|
PLAT::wait_until(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_irq(short id, bool value) {
|
void local_irq(short id, bool value) {
|
||||||
reg_t mask = 0;
|
reg_t mask = 0;
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 16: // SW
|
case 3: // SW
|
||||||
mask = 1 << 3;
|
mask = 1 << 3;
|
||||||
break;
|
break;
|
||||||
case 17: // timer
|
case 7: // timer
|
||||||
mask = 1 << 7;
|
mask = 1 << 7;
|
||||||
break;
|
break;
|
||||||
case 18: // external
|
case 11: // external
|
||||||
mask = 1 << 11;
|
mask = 1 << 11;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* do nothing*/
|
if(id>15) mask = 1 << id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -226,7 +207,7 @@ public:
|
|||||||
this->csr[arch::mip] &= ~mask;
|
this->csr[arch::mip] &= ~mask;
|
||||||
this->check_interrupt();
|
this->check_interrupt();
|
||||||
if(value)
|
if(value)
|
||||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->pending_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -350,6 +331,7 @@ SC_HAS_PROCESS(core_complex);// NOLINT
|
|||||||
#ifndef CWR_SYSTEMC
|
#ifndef CWR_SYSTEMC
|
||||||
core_complex::core_complex(sc_module_name const& name)
|
core_complex::core_complex(sc_module_name const& name)
|
||||||
: sc_module(name)
|
: sc_module(name)
|
||||||
|
, fetch_lut(tlm_dmi_ext())
|
||||||
, read_lut(tlm_dmi_ext())
|
, read_lut(tlm_dmi_ext())
|
||||||
, write_lut(tlm_dmi_ext())
|
, write_lut(tlm_dmi_ext())
|
||||||
{
|
{
|
||||||
@ -359,7 +341,13 @@ core_complex::core_complex(sc_module_name const& name)
|
|||||||
|
|
||||||
void core_complex::init(){
|
void core_complex::init(){
|
||||||
trc=new core_trace();
|
trc=new core_trace();
|
||||||
initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||||
|
auto lut_entry = fetch_lut.getEntry(start);
|
||||||
|
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
|
||||||
|
fetch_lut.removeEntry(lut_entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dbus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||||
auto lut_entry = read_lut.getEntry(start);
|
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) {
|
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) {
|
||||||
read_lut.removeEntry(lut_entry);
|
read_lut.removeEntry(lut_entry);
|
||||||
@ -377,8 +365,11 @@ void core_complex::init(){
|
|||||||
sensitive << sw_irq_i;
|
sensitive << sw_irq_i;
|
||||||
SC_METHOD(timer_irq_cb);
|
SC_METHOD(timer_irq_cb);
|
||||||
sensitive << timer_irq_i;
|
sensitive << timer_irq_i;
|
||||||
SC_METHOD(global_irq_cb);
|
SC_METHOD(ext_irq_cb);
|
||||||
sensitive << global_irq_i;
|
sensitive << ext_irq_i;
|
||||||
|
SC_METHOD(local_irq_cb);
|
||||||
|
for(auto pin:local_irq_i)
|
||||||
|
sensitive << pin;
|
||||||
trc->m_db=scv_tr_db::get_default_db();
|
trc->m_db=scv_tr_db::get_default_db();
|
||||||
|
|
||||||
SC_METHOD(forward);
|
SC_METHOD(forward);
|
||||||
@ -427,10 +418,11 @@ void core_complex::before_end_of_elaboration() {
|
|||||||
cpu->vm->register_plugin(*plugin);
|
cpu->vm->register_plugin(*plugin);
|
||||||
plugin_list.push_back(plugin);
|
plugin_list.push_back(plugin);
|
||||||
} else if (plugin_name == "pctrace") {
|
} else if (plugin_name == "pctrace") {
|
||||||
auto *plugin = new iss::plugin::cov(filename);
|
auto *plugin = new iss::plugin::pctrace(filename);
|
||||||
cpu->vm->register_plugin(*plugin);
|
cpu->vm->register_plugin(*plugin);
|
||||||
plugin_list.push_back(plugin);
|
plugin_list.push_back(plugin);
|
||||||
} else {
|
} else {
|
||||||
|
#ifndef WIN32
|
||||||
std::array<char const*, 1> a{{filename.c_str()}};
|
std::array<char const*, 1> a{{filename.c_str()}};
|
||||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||||
@ -438,6 +430,7 @@ void core_complex::before_end_of_elaboration() {
|
|||||||
cpu->vm->register_plugin(*plugin);
|
cpu->vm->register_plugin(*plugin);
|
||||||
plugin_list.push_back(plugin);
|
plugin_list.push_back(plugin);
|
||||||
} else
|
} else
|
||||||
|
#endif
|
||||||
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
|
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,7 +439,7 @@ void core_complex::before_end_of_elaboration() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void core_complex::start_of_simulation() {
|
void core_complex::start_of_simulation() {
|
||||||
quantum_keeper.reset();
|
// quantum_keeper.reset();
|
||||||
if (GET_PROP_VALUE(elf_file).size() > 0) {
|
if (GET_PROP_VALUE(elf_file).size() > 0) {
|
||||||
istringstream is(GET_PROP_VALUE(elf_file));
|
istringstream is(GET_PROP_VALUE(elf_file));
|
||||||
string s;
|
string s;
|
||||||
@ -498,15 +491,24 @@ void core_complex::rst_cb() {
|
|||||||
if (rst_i.read()) cpu->set_interrupt_execution(true);
|
if (rst_i.read()) cpu->set_interrupt_execution(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void core_complex::sw_irq_cb() { cpu->local_irq(16, sw_irq_i.read()); }
|
void core_complex::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); }
|
||||||
|
|
||||||
void core_complex::timer_irq_cb() { cpu->local_irq(17, timer_irq_i.read()); }
|
void core_complex::timer_irq_cb() { cpu->local_irq(7, timer_irq_i.read()); }
|
||||||
|
|
||||||
void core_complex::global_irq_cb() { cpu->local_irq(18, global_irq_i.read()); }
|
void core_complex::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); }
|
||||||
|
|
||||||
|
void core_complex::local_irq_cb() {
|
||||||
|
for(auto i=0U; i<local_irq_i.size(); ++i) {
|
||||||
|
if(local_irq_i[i].event()) {
|
||||||
|
cpu->local_irq(16+i, local_irq_i[i].read());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void core_complex::run() {
|
void core_complex::run() {
|
||||||
wait(SC_ZERO_TIME); // separate from elaboration phase
|
wait(SC_ZERO_TIME); // separate from elaboration phase
|
||||||
do {
|
do {
|
||||||
|
wait(SC_ZERO_TIME);
|
||||||
if (rst_i.read()) {
|
if (rst_i.read()) {
|
||||||
cpu->reset(GET_PROP_VALUE(reset_address));
|
cpu->reset(GET_PROP_VALUE(reset_address));
|
||||||
wait(rst_i.negedge_event());
|
wait(rst_i.negedge_event());
|
||||||
@ -514,6 +516,7 @@ void core_complex::run() {
|
|||||||
while (curr_clk.read() == SC_ZERO_TIME) {
|
while (curr_clk.read() == SC_ZERO_TIME) {
|
||||||
wait(curr_clk.value_changed_event());
|
wait(curr_clk.value_changed_event());
|
||||||
}
|
}
|
||||||
|
quantum_keeper.reset();
|
||||||
cpu->set_interrupt_execution(false);
|
cpu->set_interrupt_execution(false);
|
||||||
cpu->start();
|
cpu->start();
|
||||||
} while (cpu->get_interrupt_execution());
|
} while (cpu->get_interrupt_execution());
|
||||||
@ -521,14 +524,15 @@ void core_complex::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch) {
|
bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch) {
|
||||||
auto lut_entry = read_lut.getEntry(addr);
|
auto& dmi_lut = is_fetch?fetch_lut:read_lut;
|
||||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
auto lut_entry = dmi_lut.getEntry(addr);
|
||||||
addr + length <= lut_entry.get_end_address() + 1) {
|
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
|
||||||
auto offset = addr - lut_entry.get_start_address();
|
auto offset = addr - lut_entry.get_start_address();
|
||||||
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
||||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
quantum_keeper.inc(lut_entry.get_read_latency());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
auto& sckt = is_fetch? ibus : dbus;
|
||||||
tlm::tlm_generic_payload gp;
|
tlm::tlm_generic_payload gp;
|
||||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||||
gp.set_address(addr);
|
gp.set_address(addr);
|
||||||
@ -543,8 +547,13 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
|||||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||||
gp.set_extension(preExt);
|
gp.set_extension(preExt);
|
||||||
}
|
}
|
||||||
initiator->b_transport(gp, delay);
|
sckt->b_transport(gp, delay);
|
||||||
SCCTRACE(this->name()) << "read_mem(0x" << std::hex << addr << ") : " << data;
|
auto incr = delay-quantum_keeper.get_local_time();
|
||||||
|
if(is_fetch)
|
||||||
|
ibus_inc+=incr;
|
||||||
|
else
|
||||||
|
dbus_inc+=incr;
|
||||||
|
SCCTRACE(this->name()) << "[local time: "<<delay<<"]: finish read_mem(0x" << std::hex << addr << ") : 0x" << (length==4?*(uint32_t*)data:length==2?*(uint16_t*)data:(unsigned)*data);
|
||||||
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -552,12 +561,9 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
|||||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||||
gp.set_address(addr);
|
gp.set_address(addr);
|
||||||
tlm_dmi_ext dmi_data;
|
tlm_dmi_ext dmi_data;
|
||||||
if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
|
if (sckt->get_direct_mem_ptr(gp, dmi_data)) {
|
||||||
if (dmi_data.is_read_allowed())
|
if (dmi_data.is_read_allowed())
|
||||||
read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
dmi_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
|
||||||
if (dmi_data.is_write_allowed())
|
|
||||||
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
|
||||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -587,9 +593,9 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
|||||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
auto preExt = new tlm::scc::scv::tlm_recording_extension(trc->tr_handle, this);
|
||||||
gp.set_extension(preExt);
|
gp.set_extension(preExt);
|
||||||
}
|
}
|
||||||
initiator->b_transport(gp, delay);
|
dbus->b_transport(gp, delay);
|
||||||
quantum_keeper.set(delay);
|
dbus_inc+=delay-quantum_keeper.get_local_time();
|
||||||
SCCTRACE() << "write_mem(0x" << std::hex << addr << ") : " << data;
|
SCCTRACE() << "[local time: "<<delay<<"]: finish write_mem(0x" << std::hex << addr << ") : 0x" << (length==4?*(uint32_t*)data:length==2?*(uint16_t*)data:(unsigned)*data);
|
||||||
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
if (gp.get_response_status() != tlm::TLM_OK_RESPONSE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -597,10 +603,7 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
|||||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||||
gp.set_address(addr);
|
gp.set_address(addr);
|
||||||
tlm_dmi_ext dmi_data;
|
tlm_dmi_ext dmi_data;
|
||||||
if (initiator->get_direct_mem_ptr(gp, dmi_data)) {
|
if (dbus->get_direct_mem_ptr(gp, dmi_data)) {
|
||||||
if (dmi_data.is_read_allowed())
|
|
||||||
read_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
|
||||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
|
||||||
if (dmi_data.is_write_allowed())
|
if (dmi_data.is_write_allowed())
|
||||||
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
write_lut.addEntry(dmi_data, dmi_data.get_start_address(),
|
||||||
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
dmi_data.get_end_address() - dmi_data.get_start_address() + 1);
|
||||||
@ -611,33 +614,16 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data) {
|
bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||||
auto lut_entry = read_lut.getEntry(addr);
|
|
||||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
|
||||||
addr + length <= lut_entry.get_end_address() + 1) {
|
|
||||||
auto offset = addr - lut_entry.get_start_address();
|
|
||||||
std::copy(lut_entry.get_dmi_ptr() + offset, lut_entry.get_dmi_ptr() + offset + length, data);
|
|
||||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
tlm::tlm_generic_payload gp;
|
tlm::tlm_generic_payload gp;
|
||||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||||
gp.set_address(addr);
|
gp.set_address(addr);
|
||||||
gp.set_data_ptr(data);
|
gp.set_data_ptr(data);
|
||||||
gp.set_data_length(length);
|
gp.set_data_length(length);
|
||||||
gp.set_streaming_width(length);
|
gp.set_streaming_width(length);
|
||||||
return initiator->transport_dbg(gp) == length;
|
return dbus->transport_dbg(gp) == length;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data) {
|
bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||||
auto lut_entry = write_lut.getEntry(addr);
|
|
||||||
if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE &&
|
|
||||||
addr + length <= lut_entry.get_end_address() + 1) {
|
|
||||||
auto offset = addr - lut_entry.get_start_address();
|
|
||||||
std::copy(data, data + length, lut_entry.get_dmi_ptr() + offset);
|
|
||||||
quantum_keeper.inc(lut_entry.get_read_latency());
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
write_buf.resize(length);
|
write_buf.resize(length);
|
||||||
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
|
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
|
||||||
tlm::tlm_generic_payload gp;
|
tlm::tlm_generic_payload gp;
|
||||||
@ -646,8 +632,7 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
|
|||||||
gp.set_data_ptr(write_buf.data());
|
gp.set_data_ptr(write_buf.data());
|
||||||
gp.set_data_length(length);
|
gp.set_data_length(length);
|
||||||
gp.set_streaming_width(length);
|
gp.set_streaming_width(length);
|
||||||
return initiator->transport_dbg(gp) == length;
|
return dbus->transport_dbg(gp) == length;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} /* namespace SiFive */
|
} /* namespace SiFive */
|
||||||
} /* namespace sysc */
|
} /* namespace sysc */
|
||||||
|
@ -40,8 +40,10 @@
|
|||||||
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
|
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
|
||||||
#ifdef CWR_SYSTEMC
|
#ifdef CWR_SYSTEMC
|
||||||
#include <scmlinc/scml_property.h>
|
#include <scmlinc/scml_property.h>
|
||||||
|
#define SOCKET_WIDTH 32
|
||||||
#else
|
#else
|
||||||
#include <cci_configuration>
|
#include <cci_configuration>
|
||||||
|
#define SOCKET_WIDTH scc::LT
|
||||||
#endif
|
#endif
|
||||||
#include <tlm>
|
#include <tlm>
|
||||||
#include <tlm_utils/tlm_quantumkeeper.h>
|
#include <tlm_utils/tlm_quantumkeeper.h>
|
||||||
@ -69,11 +71,13 @@ struct core_trace;
|
|||||||
|
|
||||||
class core_complex : public sc_core::sc_module, public scc::traceable {
|
class core_complex : public sc_core::sc_module, public scc::traceable {
|
||||||
public:
|
public:
|
||||||
tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> ibus{"ibus"};
|
||||||
|
|
||||||
|
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> dbus{"dbus"};
|
||||||
|
|
||||||
sc_core::sc_in<bool> rst_i{"rst_i"};
|
sc_core::sc_in<bool> rst_i{"rst_i"};
|
||||||
|
|
||||||
sc_core::sc_in<bool> global_irq_i{"global_irq_i"};
|
sc_core::sc_in<bool> ext_irq_i{"ext_irq_i"};
|
||||||
|
|
||||||
sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"};
|
sc_core::sc_in<bool> timer_irq_i{"timer_irq_i"};
|
||||||
|
|
||||||
@ -84,7 +88,7 @@ public:
|
|||||||
#ifndef CWR_SYSTEMC
|
#ifndef CWR_SYSTEMC
|
||||||
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
||||||
|
|
||||||
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o;
|
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o{"mtime_o"};
|
||||||
|
|
||||||
cci::cci_param<std::string> elf_file{"elf_file", ""};
|
cci::cci_param<std::string> elf_file{"elf_file", ""};
|
||||||
|
|
||||||
@ -140,6 +144,8 @@ public:
|
|||||||
, gdb_server_port{"gdb_server_port", 0}
|
, gdb_server_port{"gdb_server_port", 0}
|
||||||
, dump_ir{"dump_ir", false}
|
, dump_ir{"dump_ir", false}
|
||||||
, mhartid{"mhartid", 0}
|
, mhartid{"mhartid", 0}
|
||||||
|
, plugins{"plugins", ""}
|
||||||
|
, fetch_lut(tlm_dmi_ext())
|
||||||
, read_lut(tlm_dmi_ext())
|
, read_lut(tlm_dmi_ext())
|
||||||
, write_lut(tlm_dmi_ext())
|
, write_lut(tlm_dmi_ext())
|
||||||
{
|
{
|
||||||
@ -151,13 +157,16 @@ public:
|
|||||||
~core_complex();
|
~core_complex();
|
||||||
|
|
||||||
inline void sync(uint64_t cycle) {
|
inline void sync(uint64_t cycle) {
|
||||||
auto time = curr_clk * (cycle - last_sync_cycle);
|
auto core_inc = curr_clk * (cycle - last_sync_cycle);
|
||||||
quantum_keeper.inc(time);
|
auto incr = std::max(core_inc, std::max(ibus_inc, dbus_inc));
|
||||||
|
quantum_keeper.inc(incr);
|
||||||
if (quantum_keeper.need_sync()) {
|
if (quantum_keeper.need_sync()) {
|
||||||
wait(quantum_keeper.get_local_time());
|
wait(quantum_keeper.get_local_time());
|
||||||
quantum_keeper.reset();
|
quantum_keeper.reset();
|
||||||
}
|
}
|
||||||
last_sync_cycle = cycle;
|
last_sync_cycle = cycle;
|
||||||
|
ibus_inc = sc_core::SC_ZERO_TIME;
|
||||||
|
dbus_inc = sc_core::SC_ZERO_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch);
|
bool read_mem(uint64_t addr, unsigned length, uint8_t *const data, bool is_fetch);
|
||||||
@ -181,13 +190,15 @@ protected:
|
|||||||
void rst_cb();
|
void rst_cb();
|
||||||
void sw_irq_cb();
|
void sw_irq_cb();
|
||||||
void timer_irq_cb();
|
void timer_irq_cb();
|
||||||
void global_irq_cb();
|
void ext_irq_cb();
|
||||||
|
void local_irq_cb();
|
||||||
uint64_t last_sync_cycle = 0;
|
uint64_t last_sync_cycle = 0;
|
||||||
util::range_lut<tlm_dmi_ext> read_lut, write_lut;
|
util::range_lut<tlm_dmi_ext> fetch_lut, read_lut, write_lut;
|
||||||
tlm_utils::tlm_quantumkeeper quantum_keeper;
|
tlm_utils::tlm_quantumkeeper quantum_keeper;
|
||||||
std::vector<uint8_t> write_buf;
|
std::vector<uint8_t> write_buf;
|
||||||
core_wrapper* cpu{nullptr};
|
core_wrapper* cpu{nullptr};
|
||||||
sc_core::sc_signal<sc_core::sc_time> curr_clk;
|
sc_core::sc_signal<sc_core::sc_time> curr_clk;
|
||||||
|
sc_core::sc_time ibus_inc, dbus_inc;
|
||||||
core_trace* trc{nullptr};
|
core_trace* trc{nullptr};
|
||||||
std::unique_ptr<scc::tick2time> t2t;
|
std::unique_ptr<scc::tick2time> t2t;
|
||||||
private:
|
private:
|
||||||
@ -195,7 +206,7 @@ private:
|
|||||||
std::vector<iss::vm_plugin *> plugin_list;
|
std::vector<iss::vm_plugin *> plugin_list;
|
||||||
|
|
||||||
};
|
};
|
||||||
} /* namespace SiFive */
|
} /* namespace tgfs */
|
||||||
} /* namespace sysc */
|
} /* namespace sysc */
|
||||||
|
|
||||||
#endif /* _SYSC_CORE_COMPLEX_H_ */
|
#endif /* _SYSC_CORE_COMPLEX_H_ */
|
1
src/vm/interp/.gitignore
vendored
1
src/vm/interp/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/vm_tgc_*.cpp
|
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <iss/arch/tgf_c.h>
|
#include <iss/arch/tgc_c.h>
|
||||||
#include <iss/arch/riscv_hart_m_p.h>
|
#include <iss/arch/riscv_hart_m_p.h>
|
||||||
#include <iss/debugger/gdb_session.h>
|
#include <iss/debugger/gdb_session.h>
|
||||||
#include <iss/debugger/server.h>
|
#include <iss/debugger/server.h>
|
||||||
@ -52,7 +52,7 @@ namespace fp_impl {
|
|||||||
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
|
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace tgf_c {
|
namespace tgc_c {
|
||||||
using namespace ::llvm;
|
using namespace ::llvm;
|
||||||
using namespace iss::arch;
|
using namespace iss::arch;
|
||||||
using namespace iss::debugger;
|
using namespace iss::debugger;
|
||||||
@ -4151,11 +4151,11 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *b
|
|||||||
bb, this->trap_blk, 1);
|
bb, this->trap_blk, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tgf_c
|
} // namespace tgc_c
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
std::unique_ptr<vm_if> create<arch::tgf_c>(arch::tgf_c *core, unsigned short port, bool dump) {
|
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
|
||||||
auto ret = new tgf_c::vm_impl<arch::tgf_c>(*core, dump);
|
auto ret = new tgc_c::vm_impl<arch::tgc_c>(*core, dump);
|
||||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
|
||||||
return std::unique_ptr<vm_if>(ret);
|
return std::unique_ptr<vm_if>(ret);
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
3218
src/vm/tcc/vm_tgc_c.cpp
Normal file
3218
src/vm/tcc/vm_tgc_c.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user