Compare commits
150 Commits
f4f90c5e65
...
feature/ht
Author | SHA1 | Date | |
---|---|---|---|
aaebeaf023 | |||
f4718c6de3 | |||
53de21eef9 | |||
d443c89c87 | |||
9a2df32d57 | |||
be0f783af8 | |||
1089800682 | |||
a6a6f51f0b | |||
21e1f791ad | |||
be6f5791fa | |||
d907dc7f54 | |||
75e81ce236 | |||
82a70efdb8 | |||
978c3db06e | |||
0e88664ff7 | |||
ac818f304d | |||
ad60449073 | |||
b45b3589fa | |||
1fb7e8fcea | |||
5f9d0beafb | |||
4c0d1c75aa | |||
2f3abf2f76 | |||
62768bf81e | |||
f6be8ec006 | |||
a8f56b6e27 | |||
76ea0db25d | |||
ec1b820c18 | |||
64329cf0f6 | |||
9de0aed84d | |||
bb4e2766d1 | |||
0996d15bd4 | |||
6305efa7c2 | |||
de79adc50d | |||
0473aa5344 | |||
a45fcd28db | |||
0f15032210 | |||
efc11d87a5 | |||
4a19e27926 | |||
c15cdb0955 | |||
6609d12582 | |||
b5341700aa | |||
0b5062d21c | |||
fbca690b3b | |||
235a7e6e24 | |||
62d21e1156 | |||
9c51d6eade | |||
2878dca6b5 | |||
c28e8fd00c | |||
b3cc9d2346 | |||
933f08494c | |||
21f8eab432 | |||
6ddb8da07f | |||
edf456c59f | |||
42efced1eb | |||
c376e34b2b | |||
f579ec6e48 | |||
fd20e66f1f | |||
5d69b79232 | |||
2edd68d1bd | |||
7ffa7667b6 | |||
93d89e07ca | |||
17dcba4b90 | |||
39d2518fdd | |||
a365110054 | |||
d2efb23ff7 | |||
04b7a09b19 | |||
72b11beac5 | |||
e87b7d5fd0 | |||
5a2b96ef3e | |||
c6b99cd155 | |||
b1306c3a47 | |||
0d6bf924ed | |||
86de536c8f | |||
051dd5e2d3 | |||
e3942be776 | |||
6ee484a771 | |||
60808c8649 | |||
0432803d82 | |||
4f5d9214ed | |||
d42d2ce533 | |||
236d12d7f5 | |||
e1b6cab890 | |||
8361f88718 | |||
2ec7ea4b41 | |||
b24965d321 | |||
244bf6d2f2 | |||
1a4465a371 | |||
fa82a50824 | |||
6dc17857da | |||
11a30caae8 | |||
ac1a26a10c | |||
7a199e122d | |||
d8c3d2e19c | |||
375755999a | |||
9996fd4833 | |||
149b3136d2 | |||
ac8f8b0539 | |||
b2cbf90d0b | |||
373145478e | |||
55b0cea94f | |||
5b17599aa2 | |||
4cfb15c7cd | |||
63da7f8d57 | |||
fb4012fbd1 | |||
24449f1c0f | |||
fd303c8343 | |||
346b177a87 | |||
d4ec131fa7 | |||
48370a4555 | |||
36b076774e | |||
482a4ec253 | |||
2fb28364c5 | |||
8460f4ab7f | |||
3fd51cc68c | |||
551822916c | |||
37db31fb4b | |||
e2da306eee | |||
41051f8f34 | |||
2a7449fa1e | |||
a6c48ceaac | |||
1e30b68507 | |||
ed793471bb | |||
58fb815f32 | |||
3cc8bd0854 | |||
a27850f841 | |||
fb330cddea | |||
b76c5bf0d6 | |||
001c6349f7 | |||
ee6a11dae6 | |||
2e27b025cc | |||
f0a004be9d | |||
3422c7cd5c | |||
ad79a28705 | |||
9fdbc3ff38 | |||
602bc6e06a | |||
6cb76fc256 | |||
fbcd389580 | |||
b25b7848c6 | |||
6c986d38d8 | |||
a1ebd83d2a | |||
8aed551813 | |||
1e6a0086e9 | |||
119d4a8b43 | |||
9841b16122 | |||
fbda1424f3 | |||
fe2d5cb2f9 | |||
3ff59ba45d | |||
db5765b342 | |||
075e04249a | |||
207f778ee6 |
@ -1,8 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
###############################################################################
|
||||
|
||||
# ##############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
# ##############################################################################
|
||||
project(dbt-rise-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
@ -19,33 +20,41 @@ set(LIB_SOURCES
|
||||
src/iss/arch/tgc5c.cpp
|
||||
src/vm/interp/vm_tgc5c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
src/iss/debugger/csr_names.cpp
|
||||
src/iss/semihosting/semihosting.cpp
|
||||
)
|
||||
|
||||
if(WITH_TCC)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/tcc/vm_tgc5c.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_LLVM)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/llvm/vm_tgc5c.cpp
|
||||
src/vm/llvm/fp_impl.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_ASMJIT)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/vm/asmjit/vm_tgc5c.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# library files
|
||||
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
|
||||
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
|
||||
FILE(GLOB GEN_YAML_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/contrib/instr/*.yaml)
|
||||
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
|
||||
|
||||
foreach(FILEPATH ${GEN_ISS_SOURCES})
|
||||
get_filename_component(CORE ${FILEPATH} NAME_WE)
|
||||
string(TOUPPER ${CORE} CORE)
|
||||
list(APPEND LIB_DEFINES CORE_${CORE})
|
||||
endforeach()
|
||||
|
||||
message(STATUS "Core defines are ${LIB_DEFINES}")
|
||||
|
||||
if(WITH_LLVM)
|
||||
@ -57,16 +66,19 @@ if(WITH_TCC)
|
||||
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
if(WITH_ASMJIT)
|
||||
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/asmjit/vm_*.cpp)
|
||||
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
|
||||
endif()
|
||||
|
||||
if(TARGET yaml-cpp::yaml-cpp)
|
||||
list(APPEND LIB_SOURCES
|
||||
src/iss/plugin/cycle_estimate.cpp
|
||||
src/iss/plugin/instruction_count.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# Define the library
|
||||
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
|
||||
|
||||
@ -75,33 +87,28 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
|
||||
|
||||
target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core)
|
||||
|
||||
# only re-export the include paths
|
||||
get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL})
|
||||
get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS)
|
||||
if(NOT (DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND))
|
||||
|
||||
if(NOT(DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND))
|
||||
target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)
|
||||
|
||||
if(TARGET yaml-cpp::yaml-cpp)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp)
|
||||
endif()
|
||||
|
||||
if(WITH_LLVM)
|
||||
find_package(LLVM)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS})
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_link_libraries( ${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
@ -119,16 +126,18 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory
|
||||
FILES_MATCHING # install only matched files
|
||||
PATTERN "*.h" # select header files
|
||||
)
|
||||
)
|
||||
install(FILES ${GEN_YAML_SOURCES} DESTINATION share/tgc-vp)
|
||||
###############################################################################
|
||||
|
||||
# ##############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
# ##############################################################################
|
||||
set(CMAKE_INSTALL_RPATH $ORIGIN/../${CMAKE_INSTALL_LIBDIR})
|
||||
project(tgc-sim)
|
||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||
|
||||
if(TARGET ${CORE_NAME}_cpp)
|
||||
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
|
||||
else()
|
||||
@ -140,21 +149,20 @@ else()
|
||||
endif()
|
||||
|
||||
foreach(F IN LISTS TGC_SOURCES)
|
||||
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
if(${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
#if(WITH_LLVM)
|
||||
# if(WITH_LLVM)
|
||||
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
||||
# #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
#endif()
|
||||
#if(WITH_TCC)
|
||||
# endif()
|
||||
# if(WITH_TCC)
|
||||
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
|
||||
#endif()
|
||||
|
||||
# endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)
|
||||
|
||||
if(TARGET Boost::program_options)
|
||||
@ -162,8 +170,10 @@ if(TARGET Boost::program_options)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
|
||||
if (Tcmalloc_FOUND)
|
||||
|
||||
if(Tcmalloc_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
|
||||
endif(Tcmalloc_FOUND)
|
||||
|
||||
@ -181,22 +191,26 @@ if(BUILD_TESTING)
|
||||
# ... CMake code to create tests ...
|
||||
add_test(NAME tgc-sim-interp
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp)
|
||||
|
||||
if(WITH_TCC)
|
||||
add_test(NAME tgc-sim-tcc
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc)
|
||||
endif()
|
||||
|
||||
if(WITH_LLVM)
|
||||
add_test(NAME tgc-sim-llvm
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm)
|
||||
endif()
|
||||
|
||||
if(WITH_ASMJIT)
|
||||
add_test(NAME tgc-sim-asmjit
|
||||
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend asmjit)
|
||||
endif()
|
||||
endif()
|
||||
###############################################################################
|
||||
|
||||
# ##############################################################################
|
||||
#
|
||||
###############################################################################
|
||||
# ##############################################################################
|
||||
if(TARGET scc-sysc)
|
||||
project(dbt-rise-tgc_sc VERSION 1.0.0)
|
||||
set(LIB_SOURCES
|
||||
@ -208,18 +222,20 @@ if(TARGET scc-sysc)
|
||||
add_library(${PROJECT_NAME} ${LIB_SOURCES})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
|
||||
foreach(F IN LISTS TGC_SOURCES)
|
||||
if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
if(${F} MATCHES ".*/arch/([^/]*)\.cpp")
|
||||
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
|
||||
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
endif()
|
||||
endforeach()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
|
||||
# if(WITH_LLVM)
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
# endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
|
||||
|
||||
# if(WITH_LLVM)
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
# endif()
|
||||
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
@ -237,3 +253,8 @@ if(TARGET scc-sysc)
|
||||
)
|
||||
endif()
|
||||
|
||||
project(elfio-test)
|
||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} src/elfio.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio)
|
||||
|
@ -349,7 +349,7 @@ Zifencei:
|
||||
size: 32
|
||||
branch: false
|
||||
delay: 1
|
||||
RV32M:
|
||||
RVM:
|
||||
MUL:
|
||||
index: 49
|
||||
encoding: 0b00000010000000000000000000110011
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* Copyright (C) 2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -47,10 +47,10 @@ def getRegisterSizes(){
|
||||
|
||||
using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
constexpr std::array<const char*, ${registers.size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
|
||||
constexpr std::array<const char*, ${registers.size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
|
||||
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2021 MINRES Technologies GmbH
|
||||
* Copyright (C) 2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -75,10 +75,10 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_names{
|
||||
static constexpr std::array<const char*, ${registers.size()}> reg_names{
|
||||
{"${registers.collect{it.name.toLowerCase()}.join('", "')}"}};
|
||||
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_aliases{
|
||||
static constexpr std::array<const char*, ${registers.size()}> reg_aliases{
|
||||
{"${registers.collect{it.alias.toLowerCase()}.join('", "')}"}};
|
||||
|
||||
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
|
||||
@ -99,17 +99,17 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, ${getRegisterSizes().size}> reg_bit_widths{
|
||||
static constexpr std::array<const uint32_t, ${getRegisterSizes().size()}> reg_bit_widths{
|
||||
{${getRegisterSizes().join(',')}}};
|
||||
|
||||
static constexpr std::array<const uint32_t, ${getRegisterOffsets().size}> reg_byte_offsets{
|
||||
static constexpr std::array<const uint32_t, ${getRegisterOffsets().size()}> reg_byte_offsets{
|
||||
{${getRegisterOffsets().join(',')}}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')}, IMEM = MEM };
|
||||
|
||||
enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %>
|
||||
${instr.instruction.name} = ${index},<%}%>
|
||||
@ -131,8 +131,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
@ -141,8 +139,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ${coreDef.name}_regs {<%
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2023 MINRES Technologies GmbH
|
||||
* Copyright (C) 2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -45,17 +45,17 @@ namespace interp {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%}%>
|
||||
@ -66,17 +66,17 @@ namespace llvm {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%}%>
|
||||
@ -88,17 +88,17 @@ namespace tcc {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%}%>
|
||||
@ -110,17 +110,17 @@ namespace asmjit {
|
||||
using namespace sysc;
|
||||
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = {
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%if(coreDef.name.toLowerCase()=="tgc5d" || coreDef.name.toLowerCase()=="tgc5e") {%>,
|
||||
iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p_clic_pmp|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto* cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_EXT_N | iss::arch::FEAT_CLIC)>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
|
||||
})<%}%>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2023 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017-2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -37,7 +37,10 @@
|
||||
#include <iss/asmjit/vm_base.h>
|
||||
#include <asmjit/asmjit.h>
|
||||
#include <util/logging.h>
|
||||
|
||||
#include <iss/instruction_decoder.h>
|
||||
<%def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
#include <vm/fp_functions.h><%}%>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -79,12 +82,33 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
using vm_base<ARCH>::get_reg_ptr;
|
||||
using super::get_ptr_for;
|
||||
using super::get_reg_for;
|
||||
using super::get_reg_for_Gp;
|
||||
using super::load_reg_from_mem;
|
||||
using super::load_reg_from_mem_Gp;
|
||||
using super::write_reg_to_mem;
|
||||
using super::gen_read_mem;
|
||||
using super::gen_write_mem;
|
||||
using super::gen_leave;
|
||||
using super::gen_sync;
|
||||
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
|
||||
|
||||
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
|
||||
continuation_e gen_single_inst_behavior(virt_addr_t&, jit_holder&) override;
|
||||
enum globals_e {TVAL = 0, GLOBALS_SIZE};
|
||||
void gen_block_prologue(jit_holder& jh) override;
|
||||
void gen_block_epilogue(jit_holder& jh) override;
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
<%if(fcsr != null) {%>
|
||||
inline const char *fname(size_t index){return index < 32?name(index+traits::F0):"illegal";}
|
||||
<%}%>
|
||||
void gen_instr_prologue(jit_holder& jh);
|
||||
void gen_instr_epilogue(jit_holder& jh);
|
||||
inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause);
|
||||
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> void gen_set_tval(jit_holder& jh, T new_tval) ;
|
||||
void gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) ;
|
||||
|
||||
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||
inline S sext(U from) {
|
||||
@ -92,34 +116,29 @@ protected:
|
||||
auto sign_mask = 1ULL<<(W-1);
|
||||
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||
}
|
||||
#include <vm/asmjit/helper_func.h>
|
||||
|
||||
<%functions.each{ it.eachLine { %>
|
||||
${it}<%}%>
|
||||
<%}%>
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
decoding_tree_node* root {nullptr};
|
||||
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
//needs to be declared after instr_descr
|
||||
decoder instr_decoder;
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
|
||||
@ -127,105 +146,82 @@ private:
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate disass */
|
||||
<%instr.disass.eachLine{%>
|
||||
${it}<%}%>
|
||||
InvokeNode* call_print_disass;
|
||||
char* mnemonic_ptr = strdup(mnemonic.c_str());
|
||||
jh.disass_collection.push_back(mnemonic_ptr);
|
||||
jh.cc.invoke(&call_print_disass, &print_disass, FuncSignature::build<void, void *, uint64_t, char *>());
|
||||
call_print_disass->setArg(0, jh.arch_if_ptr);
|
||||
call_print_disass->setArg(1, pc.val);
|
||||
call_print_disass->setArg(2, mnemonic_ptr);
|
||||
|
||||
}
|
||||
x86::Compiler& cc = jh.cc;
|
||||
//ideally only do this if necessary (someone / plugin needs it)
|
||||
cc.mov(jh.pc,PC);
|
||||
cc.comment(fmt::format("\\n${instr.name}_{:#x}:",pc.val).c_str());
|
||||
this->gen_sync(jh, PRE_SYNC, ${idx});
|
||||
pc=pc+ ${instr.length/8};
|
||||
cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str());
|
||||
gen_sync(jh, PRE_SYNC, ${idx});
|
||||
mov(cc, jh.pc, pc.val);
|
||||
gen_set_tval(jh, instr);
|
||||
pc = pc+${instr.length/8};
|
||||
mov(cc, jh.next_pc, pc.val);
|
||||
|
||||
gen_instr_prologue(jh, pc.val);
|
||||
cc.comment("\\n//behavior:");
|
||||
gen_instr_prologue(jh);
|
||||
cc.comment("//behavior:");
|
||||
/*generate behavior*/
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>
|
||||
gen_sync(jh, POST_SYNC, ${idx});
|
||||
gen_instr_epilogue(jh);
|
||||
this->gen_sync(jh, POST_SYNC, ${idx});
|
||||
return returnValue;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
|
||||
|
||||
return BRANCH;
|
||||
continuation_e illegal_instruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
if(this->disass_enabled){
|
||||
auto mnemonic = std::string("illegal_instruction");
|
||||
InvokeNode* call_print_disass;
|
||||
char* mnemonic_ptr = strdup(mnemonic.c_str());
|
||||
jh.disass_collection.push_back(mnemonic_ptr);
|
||||
jh.cc.invoke(&call_print_disass, &print_disass, FuncSignature::build<void, void *, uint64_t, char *>());
|
||||
call_print_disass->setArg(0, jh.arch_if_ptr);
|
||||
call_print_disass->setArg(1, pc.val);
|
||||
call_print_disass->setArg(2, mnemonic_ptr);
|
||||
}
|
||||
//decoding functionality
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
cc.comment(fmt::format("illegal_instruction{:#x}:",pc.val).c_str());
|
||||
gen_sync(jh, PRE_SYNC, instr_descr.size());
|
||||
mov(cc, jh.pc, pc.val);
|
||||
gen_set_tval(jh, instr);
|
||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
mov(cc, jh.next_pc, pc.val);
|
||||
gen_instr_prologue(jh);
|
||||
cc.comment("//behavior:");
|
||||
gen_raise(jh, 0, 2);
|
||||
gen_sync(jh, POST_SYNC, instr_descr.size());
|
||||
gen_instr_epilogue(jh);
|
||||
return ILLEGAL_INSTR;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||
volatile CODE_WORD x = instr;
|
||||
instr = 2 * x;
|
||||
}
|
||||
|
||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr: instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
: vm_base<ARCH>(core, core_id, cluster_id)
|
||||
, instr_decoder([this]() {
|
||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
||||
g_instr_descr.reserve(instr_descr.size());
|
||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
||||
g_instr_descr.push_back(new_instr_descr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
}
|
||||
return std::move(g_instr_descr);
|
||||
}()) {}
|
||||
|
||||
template <typename ARCH>
|
||||
continuation_e
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
|
||||
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, jit_holder& jh) {
|
||||
enum {TRAP_ID=1<<16};
|
||||
code_word_t instr = 0;
|
||||
phys_addr_t paddr(pc);
|
||||
@ -234,19 +230,104 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
paddr = this->core.virt2phys(pc);
|
||||
auto res = this->core.read(paddr, 4, data);
|
||||
if (res != iss::Ok)
|
||||
throw trap_access(TRAP_ID, pc.val);
|
||||
return ILLEGAL_FETCH;
|
||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
||||
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
++inst_cnt;
|
||||
auto f = decode_instr(root, instr);
|
||||
return JUMP_TO_SELF;
|
||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
||||
compile_func f = nullptr;
|
||||
if(inst_index < instr_descr.size())
|
||||
f = instr_descr[inst_index].op;
|
||||
if (f == nullptr)
|
||||
f = &this_class::illegal_intruction;
|
||||
f = &this_class::illegal_instruction;
|
||||
return (this->*f)(pc, instr, jh);
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_instr_prologue(jit_holder& jh) {
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("//gen_instr_prologue");
|
||||
|
||||
x86_reg_t current_trap_state = get_reg_for(cc, traits::TRAP_STATE);
|
||||
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
|
||||
mov(cc, get_ptr_for(jh, traits::PENDING_TRAP), current_trap_state);
|
||||
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_instr_epilogue(jit_holder& jh) {
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("//gen_instr_epilogue");
|
||||
x86_reg_t current_trap_state = get_reg_for(cc, traits::TRAP_STATE);
|
||||
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
|
||||
cmp(cc, current_trap_state, 0);
|
||||
cc.jne(jh.trap_entry);
|
||||
cc.inc(get_ptr_for(jh, traits::ICOUNT));
|
||||
cc.inc(get_ptr_for(jh, traits::CYCLE));
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
|
||||
jh.pc = load_reg_from_mem_Gp(jh, traits::PC);
|
||||
jh.next_pc = load_reg_from_mem_Gp(jh, traits::NEXT_PC);
|
||||
jh.globals.resize(GLOBALS_SIZE);
|
||||
jh.globals[TVAL] = get_reg_Gp(jh.cc, 64, false);
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
||||
x86::Compiler& cc = jh.cc;
|
||||
cc.comment("//gen_block_epilogue");
|
||||
cc.ret(jh.next_pc);
|
||||
|
||||
cc.bind(jh.trap_entry);
|
||||
this->write_back(jh);
|
||||
|
||||
x86::Gp current_trap_state = get_reg_for_Gp(cc, traits::TRAP_STATE);
|
||||
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
|
||||
|
||||
x86::Gp current_pc = get_reg_for_Gp(cc, traits::PC);
|
||||
mov(cc, current_pc, get_ptr_for(jh, traits::PC));
|
||||
|
||||
cc.comment("//enter trap call;");
|
||||
InvokeNode* call_enter_trap;
|
||||
cc.invoke(&call_enter_trap, &enter_trap, FuncSignature::build<uint64_t, void*, uint64_t, uint64_t, uint64_t>());
|
||||
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
||||
call_enter_trap->setArg(1, current_trap_state);
|
||||
call_enter_trap->setArg(2, current_pc);
|
||||
call_enter_trap->setArg(3, jh.globals[TVAL]);
|
||||
|
||||
x86_reg_t current_next_pc = get_reg_for(cc, traits::NEXT_PC);
|
||||
mov(cc, current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
|
||||
mov(cc, jh.next_pc, current_next_pc);
|
||||
|
||||
mov(cc, get_ptr_for(jh, traits::LAST_BRANCH), static_cast<int>(UNKNOWN_JUMP));
|
||||
cc.ret(jh.next_pc);
|
||||
}
|
||||
template <typename ARCH>
|
||||
inline void vm_impl<ARCH>::gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) {
|
||||
auto& cc = jh.cc;
|
||||
cc.comment("//gen_raise");
|
||||
auto tmp1 = get_reg_for(cc, traits::TRAP_STATE);
|
||||
mov(cc, tmp1, 0x80ULL << 24 | (cause << 16) | trap_id);
|
||||
mov(cc, get_ptr_for(jh, traits::TRAP_STATE), tmp1);
|
||||
cc.jmp(jh.trap_entry);
|
||||
}
|
||||
template <typename ARCH>
|
||||
template <typename T, typename>
|
||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, T new_tval) {
|
||||
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
||||
if(nonstd::holds_alternative<x86::Gp>(_new_tval)) {
|
||||
x86::Gp new_tval = nonstd::get<x86::Gp>(_new_tval);
|
||||
if(new_tval.size() < 8)
|
||||
new_tval = gen_ext_Gp(jh.cc, new_tval, 64, false);
|
||||
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||
} else {
|
||||
throw std::runtime_error("Variant not supported in gen_set_tval");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tgc5c
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
@ -257,22 +338,30 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
} // namespace asmjit
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
#include <iss/factory.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
auto vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
auto vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017-2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -35,6 +35,7 @@ def nativeTypeSize(int size){
|
||||
}
|
||||
%>
|
||||
// clang-format off
|
||||
#include <cstdint>
|
||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/server.h>
|
||||
@ -47,6 +48,8 @@ def nativeTypeSize(int size){
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iss/instruction_decoder.h>
|
||||
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
@ -97,7 +100,12 @@ protected:
|
||||
using compile_ret_t = virt_addr_t;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
||||
|
||||
inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
<%
|
||||
def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
inline const char *fname(size_t index){return index < 32?name(index+traits::F0):"illegal";}
|
||||
<%}%>
|
||||
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
|
||||
@ -106,7 +114,6 @@ protected:
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->core.reg.trap_state = trap_val;
|
||||
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max();
|
||||
}
|
||||
|
||||
inline void leave(unsigned lvl){
|
||||
@ -117,6 +124,13 @@ protected:
|
||||
this->core.wait_until(type);
|
||||
}
|
||||
|
||||
inline void set_tval(uint64_t new_tval){
|
||||
tval = new_tval;
|
||||
}
|
||||
|
||||
uint64_t fetch_count{0};
|
||||
uint64_t tval{0};
|
||||
|
||||
using yield_t = boost::coroutines2::coroutine<void>::push_type;
|
||||
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
|
||||
std::vector<coro_t> spawn_blocks;
|
||||
@ -146,25 +160,20 @@ private:
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
typename arch::traits<ARCH>::opcode_e op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
decoding_tree_node* root {nullptr};
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
//needs to be declared after instr_descr
|
||||
decoder instr_decoder;
|
||||
|
||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||
if(this->core.has_mmu()) {
|
||||
auto phys_pc = this->core.virt2phys(pc);
|
||||
@ -184,66 +193,12 @@ private:
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
typename arch::traits<ARCH>::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
volatile CODE_WORD x = insn;
|
||||
insn = 2 * x;
|
||||
}
|
||||
|
||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
// according to
|
||||
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
||||
#ifdef __GCC__
|
||||
@ -260,16 +215,23 @@ constexpr size_t bit_count(uint32_t u) {
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr:instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
: vm_base<ARCH>(core, core_id, cluster_id)
|
||||
, instr_decoder([this]() {
|
||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
||||
g_instr_descr.reserve(instr_descr.size());
|
||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
||||
g_instr_descr.push_back(new_instr_descr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
return std::move(g_instr_descr);
|
||||
}()) {}
|
||||
|
||||
inline bool is_icount_limit_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::ICOUNT_LIMIT) == finish_cond_e::ICOUNT_LIMIT;
|
||||
}
|
||||
|
||||
inline bool is_count_limit_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT;
|
||||
inline bool is_fcount_limit_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::FCOUNT_LIMIT) == finish_cond_e::FCOUNT_LIMIT;
|
||||
}
|
||||
|
||||
inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
||||
@ -277,7 +239,7 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
||||
}
|
||||
|
||||
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 count_limit){
|
||||
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]);
|
||||
@ -290,14 +252,24 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
auto *const data = reinterpret_cast<uint8_t*>(&instr);
|
||||
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && icount >= icount_limit)){
|
||||
!(is_icount_limit_enabled(cond) && icount >= count_limit) &&
|
||||
!(is_fcount_limit_enabled(cond) && fetch_count >= count_limit)){
|
||||
if(this->debugging_enabled())
|
||||
this->tgt_adapter->check_continue(*PC);
|
||||
pc.val=*PC;
|
||||
if(fetch_ins(pc, data)!=iss::Ok){
|
||||
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
|
||||
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max());
|
||||
process_spawn_blocks();
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max());
|
||||
pc.val = super::core.enter_trap(arch::traits<ARCH>::RV_CAUSE_FETCH_ACCESS<<16, pc.val, 0);
|
||||
} else {
|
||||
if (is_jump_to_self_enabled(cond) &&
|
||||
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto inst_id = decode_instr(root, instr);
|
||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
||||
opcode_e inst_id = arch::traits<ARCH>::opcode_e::MAX_OPCODE;;
|
||||
if(inst_index <instr_descr.size())
|
||||
inst_id = instr_descr[inst_index].op;
|
||||
|
||||
// pre execution stuff
|
||||
this->core.reg.last_branch = 0;
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
|
||||
@ -308,6 +280,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||
${it}<%}%>
|
||||
this->core.disass_output(pc.val, mnemonic);
|
||||
}
|
||||
// used registers<%instr.usedVariables.each{ k,v->
|
||||
if(v.isArray) {%>
|
||||
@ -332,16 +305,18 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
// this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
// trap check
|
||||
if(trap_state!=0){
|
||||
super::core.enter_trap(trap_state, pc.val, instr);
|
||||
//In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval)
|
||||
auto mcause = (trap_state>>16) & 0xff;
|
||||
super::core.enter_trap(trap_state, pc.val, mcause ? instr:tval);
|
||||
} else {
|
||||
icount++;
|
||||
instret++;
|
||||
}
|
||||
cycle++;
|
||||
pc.val=*NEXT_PC;
|
||||
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||
*PC = *NEXT_PC;
|
||||
this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
}
|
||||
fetch_count++;
|
||||
cycle++;
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
@ -363,16 +338,24 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017-2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -36,7 +36,10 @@
|
||||
#include <iss/iss.h>
|
||||
#include <iss/llvm/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
|
||||
#include <iss/instruction_decoder.h>
|
||||
<%def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
#include <vm/fp_functions.h><%}%>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -82,7 +85,9 @@ protected:
|
||||
using vm_base<ARCH>::get_reg_ptr;
|
||||
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
<%if(fcsr != null) {%>
|
||||
inline const char *fname(size_t index){return index < 32?name(index+traits::F0):"illegal";}
|
||||
<%}%>
|
||||
template <typename T> inline ConstantInt *size(T type) {
|
||||
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
|
||||
}
|
||||
@ -96,19 +101,17 @@ protected:
|
||||
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
|
||||
}
|
||||
|
||||
std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) override;
|
||||
std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, BasicBlock *) override;
|
||||
|
||||
void gen_leave_behavior(BasicBlock *leave_blk) override;
|
||||
|
||||
void gen_raise_trap(uint16_t trap_id, uint16_t cause);
|
||||
|
||||
void gen_leave_trap(unsigned lvl);
|
||||
|
||||
void gen_wait(unsigned type);
|
||||
|
||||
void set_tval(uint64_t new_tval);
|
||||
void set_tval(Value* new_tval);
|
||||
void gen_trap_behavior(BasicBlock *) override;
|
||||
|
||||
void gen_trap_check(BasicBlock *bb);
|
||||
void gen_instr_prologue();
|
||||
void gen_instr_epilogue(BasicBlock *bb);
|
||||
|
||||
inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
|
||||
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
|
||||
@ -132,51 +135,58 @@ protected:
|
||||
auto sign_mask = 1ULL<<(W-1);
|
||||
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||
}
|
||||
|
||||
<%functions.each{ it.eachLine { %>
|
||||
${it}<%}%>
|
||||
<%}%>
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
decoding_tree_node* root {nullptr};
|
||||
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
//needs to be declared after instr_descr
|
||||
decoder instr_decoder;
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
||||
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
|
||||
this->gen_sync(PRE_SYNC,${idx});
|
||||
uint64_t PC = pc.val;
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||
${it}<%}%>
|
||||
std::vector<Value*> args {
|
||||
this->core_ptr,
|
||||
this->gen_const(64, pc.val),
|
||||
this->builder.CreateGlobalStringPtr(mnemonic),
|
||||
};
|
||||
this->builder.CreateCall(this->mod->getFunction("print_disass"), args);
|
||||
}
|
||||
auto cur_pc_val = this->gen_const(32,pc.val);
|
||||
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
|
||||
this->gen_sync(PRE_SYNC,${idx});
|
||||
|
||||
this->gen_set_pc(pc, traits::PC);
|
||||
this->set_tval(instr);
|
||||
pc=pc+ ${instr.length/8};
|
||||
this->gen_set_pc(pc, traits::NEXT_PC);
|
||||
|
||||
this->gen_instr_prologue();
|
||||
/*generate behavior*/
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>
|
||||
this->gen_trap_check(bb);
|
||||
this->gen_sync(POST_SYNC, ${idx});
|
||||
this->gen_instr_epilogue(bb);
|
||||
this->builder.CreateBr(bb);
|
||||
return returnValue;
|
||||
}
|
||||
@ -184,7 +194,16 @@ private:
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
|
||||
std::tuple<continuation_e, BasicBlock *> illegal_instruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
|
||||
if(this->disass_enabled){
|
||||
auto mnemonic = std::string("illegal_instruction");
|
||||
std::vector<Value*> args {
|
||||
this->core_ptr,
|
||||
this->gen_const(64, pc.val),
|
||||
this->builder.CreateGlobalStringPtr(mnemonic),
|
||||
};
|
||||
this->builder.CreateCall(this->mod->getFunction("print_disass"), args);
|
||||
}
|
||||
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
|
||||
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true),
|
||||
get_reg_ptr(traits::PC), true);
|
||||
@ -193,62 +212,13 @@ private:
|
||||
this->gen_const(64U, 1)),
|
||||
get_reg_ptr(traits::ICOUNT), true);
|
||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
this->set_tval(instr);
|
||||
this->gen_raise_trap(0, 2); // illegal instruction trap
|
||||
this->gen_sync(iss::POST_SYNC, instr_descr.size());
|
||||
this->gen_trap_check(this->leave_blk);
|
||||
return std::make_tuple(BRANCH, nullptr);
|
||||
}
|
||||
//decoding functionality
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
bb = this->leave_blk;
|
||||
this->gen_instr_epilogue(bb);
|
||||
this->builder.CreateBr(bb);
|
||||
return std::make_tuple(ILLEGAL_INSTR, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
@ -261,17 +231,20 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr:instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
: vm_base<ARCH>(core, core_id, cluster_id)
|
||||
, instr_decoder([this]() {
|
||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
||||
g_instr_descr.reserve(instr_descr.size());
|
||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
||||
g_instr_descr.push_back(new_instr_descr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
}
|
||||
return std::move(g_instr_descr);
|
||||
}()) {}
|
||||
|
||||
template <typename ARCH>
|
||||
std::tuple<continuation_e, BasicBlock *>
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) {
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, BasicBlock *this_block) {
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
enum {TRAP_ID=1<<16};
|
||||
code_word_t instr = 0;
|
||||
@ -280,65 +253,83 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
auto *const data = (uint8_t *)&instr;
|
||||
if(this->core.has_mmu())
|
||||
paddr = this->core.virt2phys(pc);
|
||||
//TODO: re-add page handling
|
||||
// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
// auto res = this->core.read(paddr, 2, data);
|
||||
// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
// if ((instr & 0x3) == 0x3) { // this is a 32bit instruction
|
||||
// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
|
||||
// }
|
||||
// } else {
|
||||
auto res = this->core.read(paddr, 4, data);
|
||||
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
// }
|
||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
// curr pc on stack
|
||||
++inst_cnt;
|
||||
auto f = decode_instr(root, instr);
|
||||
if (res != iss::Ok)
|
||||
return std::make_tuple(ILLEGAL_FETCH, nullptr);
|
||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001){
|
||||
this->builder.CreateBr(this->leave_blk);
|
||||
return std::make_tuple(JUMP_TO_SELF, nullptr);
|
||||
}
|
||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
||||
compile_func f = nullptr;
|
||||
if(inst_index < instr_descr.size())
|
||||
f = instr_descr[inst_index].op;
|
||||
if (f == nullptr) {
|
||||
f = &this_class::illegal_intruction;
|
||||
f = &this_class::illegal_instruction;
|
||||
}
|
||||
return (this->*f)(pc, instr, this_block);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
|
||||
this->builder.SetInsertPoint(leave_blk);
|
||||
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
|
||||
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
|
||||
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
|
||||
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
|
||||
this->builder.CreateBr(this->trap_blk);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
|
||||
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
|
||||
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
|
||||
auto *PC_val = this->gen_read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN / 8);
|
||||
this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false);
|
||||
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
|
||||
this->builder.CreateStore(this->gen_const(32U, static_cast<int>(UNKNOWN_JUMP)), get_reg_ptr(traits::LAST_BRANCH), false);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
|
||||
this->builder.CreateCall(this->mod->getFunction("wait"), args);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
|
||||
template <typename ARCH>
|
||||
inline void vm_impl<ARCH>::set_tval(uint64_t tval) {
|
||||
auto tmp_tval = this->gen_const(64, tval);
|
||||
this->set_tval(tmp_tval);
|
||||
}
|
||||
template <typename ARCH>
|
||||
inline void vm_impl<ARCH>::set_tval(Value* new_tval) {
|
||||
this->builder.CreateStore(this->gen_ext(new_tval, 64, false), this->tval);
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
|
||||
this->builder.SetInsertPoint(trap_blk);
|
||||
this->gen_sync(POST_SYNC, -1); //TODO get right InstrId
|
||||
auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
|
||||
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
|
||||
get_reg_ptr(traits::LAST_BRANCH), false);
|
||||
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
|
||||
this->adj_to64(this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), false))};
|
||||
auto *cur_pc_val = this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), true);
|
||||
std::vector<Value *> args{this->core_ptr,
|
||||
this->adj_to64(trap_state_val),
|
||||
this->adj_to64(cur_pc_val),
|
||||
this->adj_to64(this->builder.CreateLoad(this->get_type(64),this->tval))};
|
||||
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
|
||||
this->builder.CreateStore(this->gen_const(32U, static_cast<int>(UNKNOWN_JUMP)), get_reg_ptr(traits::LAST_BRANCH), false);
|
||||
|
||||
auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false);
|
||||
this->builder.CreateRet(trap_addr_val);
|
||||
}
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_instr_prologue() {
|
||||
auto* trap_val =
|
||||
this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::PENDING_TRAP), get_reg_ptr(arch::traits<ARCH>::PENDING_TRAP));
|
||||
this->builder.CreateStore(trap_val, get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), false);
|
||||
}
|
||||
|
||||
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
|
||||
|
||||
template <typename ARCH>
|
||||
void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
|
||||
auto* target_bb = BasicBlock::Create(this->mod->getContext(), "", this->func, bb);
|
||||
auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
|
||||
this->gen_cond_branch(this->builder.CreateICmp(
|
||||
@ -346,6 +337,14 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *b
|
||||
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
|
||||
target_bb, this->trap_blk, 1);
|
||||
this->builder.SetInsertPoint(target_bb);
|
||||
// update icount
|
||||
auto* icount_val = this->builder.CreateAdd(
|
||||
this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::ICOUNT), get_reg_ptr(arch::traits<ARCH>::ICOUNT)), this->gen_const(64U, 1));
|
||||
this->builder.CreateStore(icount_val, get_reg_ptr(arch::traits<ARCH>::ICOUNT), false);
|
||||
//increment cyclecount
|
||||
auto* cycle_val = this->builder.CreateAdd(
|
||||
this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::CYCLE), get_reg_ptr(arch::traits<ARCH>::CYCLE)), this->gen_const(64U, 1));
|
||||
this->builder.CreateStore(cycle_val, get_reg_ptr(arch::traits<ARCH>::CYCLE), false);
|
||||
}
|
||||
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
@ -359,22 +358,30 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
} // namespace llvm
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
#include <iss/factory.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto* vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
auto vm = new llvm::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<std::function<void(arch_if*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*, arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t*)>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2020 MINRES Technologies GmbH
|
||||
* Copyright (C) 2020-2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -37,7 +37,10 @@
|
||||
#include <iss/tcc/vm_base.h>
|
||||
#include <util/logging.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <iss/instruction_decoder.h>
|
||||
<%def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
#include <vm/fp_functions.h><%}%>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -80,16 +83,21 @@ protected:
|
||||
using vm_base<ARCH>::get_reg_ptr;
|
||||
|
||||
using this_class = vm_impl<ARCH>;
|
||||
using compile_ret_t = std::tuple<continuation_e>;
|
||||
using compile_ret_t = continuation_e;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
|
||||
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
<%
|
||||
if(fcsr != null) {%>
|
||||
inline const char *fname(size_t index){return index < 32?name(index+traits::F0):"illegal";}
|
||||
<%}%>
|
||||
void add_prologue(tu_builder& tu) override;
|
||||
|
||||
void setup_module(std::string m) override {
|
||||
super::setup_module(m);
|
||||
}
|
||||
|
||||
compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, tu_builder&) override;
|
||||
compile_ret_t gen_single_inst_behavior(virt_addr_t &, tu_builder&) override;
|
||||
|
||||
void gen_trap_behavior(tu_builder& tu) override;
|
||||
|
||||
@ -97,7 +105,9 @@ protected:
|
||||
|
||||
void gen_leave_trap(tu_builder& tu, unsigned lvl);
|
||||
|
||||
void gen_wait(tu_builder& tu, unsigned type);
|
||||
inline void gen_set_tval(tu_builder& tu, uint64_t new_tval);
|
||||
|
||||
inline void gen_set_tval(tu_builder& tu, value new_tval);
|
||||
|
||||
inline void gen_trap_check(tu_builder& tu) {
|
||||
tu("if(*trap_state!=0) goto trap_entry;");
|
||||
@ -128,32 +138,29 @@ protected:
|
||||
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||
}
|
||||
|
||||
<%functions.each{ it.eachLine { %>
|
||||
${it}<%}%>
|
||||
<%}%>
|
||||
private:
|
||||
/****************************************************************************
|
||||
* start opcode definitions
|
||||
****************************************************************************/
|
||||
struct instruction_descriptor {
|
||||
size_t length;
|
||||
uint32_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
};
|
||||
struct decoding_tree_node{
|
||||
std::vector<instruction_descriptor> instrs;
|
||||
std::vector<decoding_tree_node*> children;
|
||||
uint32_t submask = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t value;
|
||||
decoding_tree_node(uint32_t value) : value(value){}
|
||||
};
|
||||
|
||||
decoding_tree_node* root {nullptr};
|
||||
|
||||
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
|
||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
//needs to be declared after instr_descr
|
||||
decoder instr_decoder;
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||
@ -164,82 +171,37 @@ private:
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
||||
${it}<%}%>
|
||||
tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic);
|
||||
}
|
||||
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
||||
pc=pc+ ${instr.length/8};
|
||||
gen_set_pc(tu, pc, traits::NEXT_PC);
|
||||
tu("(*cycle)++;");
|
||||
tu.open_scope();
|
||||
this->gen_set_tval(tu, instr);
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>
|
||||
tu.close_scope();
|
||||
gen_trap_check(tu);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
||||
gen_trap_check(tu);
|
||||
return returnValue;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) {
|
||||
compile_ret_t illegal_instruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) {
|
||||
vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size());
|
||||
if(this->disass_enabled){
|
||||
/* generate console output when executing the command */
|
||||
tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, std::string("illegal_instruction"));
|
||||
}
|
||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
gen_raise_trap(tu, 0, 2); // illegal instruction trap
|
||||
gen_raise_trap(tu, 0, static_cast<int32_t>(traits:: RV_CAUSE_ILLEGAL_INSTRUCTION));
|
||||
this->gen_set_tval(tu, instr);
|
||||
vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size());
|
||||
vm_impl::gen_trap_check(tu);
|
||||
return BRANCH;
|
||||
}
|
||||
|
||||
//decoding functionality
|
||||
|
||||
void populate_decoding_tree(decoding_tree_node* root){
|
||||
//create submask
|
||||
for(auto instr: root->instrs){
|
||||
root->submask &= instr.mask;
|
||||
}
|
||||
//put each instr according to submask&encoding into children
|
||||
for(auto instr: root->instrs){
|
||||
bool foundMatch = false;
|
||||
for(auto child: root->children){
|
||||
//use value as identifying trait
|
||||
if(child->value == (instr.value&root->submask)){
|
||||
child->instrs.push_back(instr);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if(!foundMatch){
|
||||
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
|
||||
child->instrs.push_back(instr);
|
||||
root->children.push_back(child);
|
||||
}
|
||||
}
|
||||
root->instrs.clear();
|
||||
//call populate_decoding_tree for all children
|
||||
if(root->children.size() >1)
|
||||
for(auto child: root->children){
|
||||
populate_decoding_tree(child);
|
||||
}
|
||||
else{
|
||||
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
|
||||
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
|
||||
return instr1.mask > instr2.mask;
|
||||
});
|
||||
}
|
||||
}
|
||||
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
|
||||
if(!node->children.size()){
|
||||
if(node->instrs.size() == 1) return node->instrs[0].op;
|
||||
for(auto instr : node->instrs){
|
||||
if((instr.mask&word) == instr.value) return instr.op;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto child : node->children){
|
||||
if (child->value == (node->submask&word)){
|
||||
return decode_instr(child, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return ILLEGAL_INSTR;
|
||||
}
|
||||
};
|
||||
|
||||
@ -252,65 +214,100 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||
for(auto instr:instr_descr){
|
||||
root->instrs.push_back(instr);
|
||||
: vm_base<ARCH>(core, core_id, cluster_id)
|
||||
, instr_decoder([this]() {
|
||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
||||
g_instr_descr.reserve(instr_descr.size());
|
||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
||||
g_instr_descr.push_back(new_instr_descr);
|
||||
}
|
||||
populate_decoding_tree(root);
|
||||
}
|
||||
return std::move(g_instr_descr);
|
||||
}()) {}
|
||||
|
||||
template <typename ARCH>
|
||||
std::tuple<continuation_e>
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
|
||||
continuation_e
|
||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, tu_builder& tu) {
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
enum {TRAP_ID=1<<16};
|
||||
code_word_t instr = 0;
|
||||
phys_addr_t paddr(pc);
|
||||
if(this->core.has_mmu())
|
||||
paddr = this->core.virt2phys(pc);
|
||||
//TODO: re-add page handling
|
||||
// if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
// auto res = this->core.read(paddr, 2, data);
|
||||
// if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
|
||||
// res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
|
||||
// }
|
||||
// } else {
|
||||
auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
|
||||
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
// }
|
||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
// curr pc on stack
|
||||
++inst_cnt;
|
||||
auto f = decode_instr(root, instr);
|
||||
if (res != iss::Ok)
|
||||
return ILLEGAL_FETCH;
|
||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
||||
return JUMP_TO_SELF;
|
||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
||||
compile_func f = nullptr;
|
||||
if(inst_index < instr_descr.size())
|
||||
f = instr_descr[inst_index].op;
|
||||
if (f == nullptr) {
|
||||
f = &this_class::illegal_intruction;
|
||||
f = &this_class::illegal_instruction;
|
||||
}
|
||||
return (this->*f)(pc, instr, tu);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(static_cast<int>(UNKNOWN_JUMP), 32));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_set_tval(tu_builder& tu, uint64_t new_tval) {
|
||||
tu(fmt::format("tval = {};", new_tval));
|
||||
}
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_set_tval(tu_builder& tu, value new_tval) {
|
||||
tu(fmt::format("tval = {};", new_tval.str));
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
this->gen_sync(tu, POST_SYNC, -1);
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc, tval);");
|
||||
tu.store(traits::LAST_BRANCH, tu.constant(static_cast<int>(UNKNOWN_JUMP),32));
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
template <typename ARCH> void vm_impl<ARCH>::add_prologue(tu_builder& tu){
|
||||
std::ostringstream os;
|
||||
os << tu.add_reg_ptr("trap_state", arch::traits<ARCH>::TRAP_STATE, this->regs_base_ptr);
|
||||
os << tu.add_reg_ptr("pending_trap", arch::traits<ARCH>::PENDING_TRAP, this->regs_base_ptr);
|
||||
os << tu.add_reg_ptr("cycle", arch::traits<ARCH>::CYCLE, this->regs_base_ptr);
|
||||
<%if(fcsr != null) {%>
|
||||
os << "uint32_t (*fget_flags)()=" << (uintptr_t)&fget_flags << ";\\n";
|
||||
os << "uint32_t (*fadd_s)(uint32_t v1, uint32_t v2, uint8_t mode)=" << (uintptr_t)&fadd_s << ";\\n";
|
||||
os << "uint32_t (*fsub_s)(uint32_t v1, uint32_t v2, uint8_t mode)=" << (uintptr_t)&fsub_s << ";\\n";
|
||||
os << "uint32_t (*fmul_s)(uint32_t v1, uint32_t v2, uint8_t mode)=" << (uintptr_t)&fmul_s << ";\\n";
|
||||
os << "uint32_t (*fdiv_s)(uint32_t v1, uint32_t v2, uint8_t mode)=" << (uintptr_t)&fdiv_s << ";\\n";
|
||||
os << "uint32_t (*fsqrt_s)(uint32_t v1, uint8_t mode)=" << (uintptr_t)&fsqrt_s << ";\\n";
|
||||
os << "uint32_t (*fcmp_s)(uint32_t v1, uint32_t v2, uint32_t op)=" << (uintptr_t)&fcmp_s << ";\\n";
|
||||
os << "uint32_t (*fcvt_s)(uint32_t v1, uint32_t op, uint8_t mode)=" << (uintptr_t)&fcvt_s << ";\\n";
|
||||
os << "uint32_t (*fmadd_s)(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode)=" << (uintptr_t)&fmadd_s << ";\\n";
|
||||
os << "uint32_t (*fsel_s)(uint32_t v1, uint32_t v2, uint32_t op)=" << (uintptr_t)&fsel_s << ";\\n";
|
||||
os << "uint32_t (*fclass_s)( uint32_t v1 )=" << (uintptr_t)&fclass_s << ";\\n";
|
||||
os << "uint32_t (*fconv_d2f)(uint64_t v1, uint8_t mode)=" << (uintptr_t)&fconv_d2f << ";\\n";
|
||||
os << "uint64_t (*fconv_f2d)(uint32_t v1, uint8_t mode)=" << (uintptr_t)&fconv_f2d << ";\\n";
|
||||
os << "uint64_t (*fadd_d)(uint64_t v1, uint64_t v2, uint8_t mode)=" << (uintptr_t)&fadd_d << ";\\n";
|
||||
os << "uint64_t (*fsub_d)(uint64_t v1, uint64_t v2, uint8_t mode)=" << (uintptr_t)&fsub_d << ";\\n";
|
||||
os << "uint64_t (*fmul_d)(uint64_t v1, uint64_t v2, uint8_t mode)=" << (uintptr_t)&fmul_d << ";\\n";
|
||||
os << "uint64_t (*fdiv_d)(uint64_t v1, uint64_t v2, uint8_t mode)=" << (uintptr_t)&fdiv_d << ";\\n";
|
||||
os << "uint64_t (*fsqrt_d)(uint64_t v1, uint8_t mode)=" << (uintptr_t)&fsqrt_d << ";\\n";
|
||||
os << "uint64_t (*fcmp_d)(uint64_t v1, uint64_t v2, uint32_t op)=" << (uintptr_t)&fcmp_d << ";\\n";
|
||||
os << "uint64_t (*fcvt_d)(uint64_t v1, uint32_t op, uint8_t mode)=" << (uintptr_t)&fcvt_d << ";\\n";
|
||||
os << "uint64_t (*fmadd_d)(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode)=" << (uintptr_t)&fmadd_d << ";\\n";
|
||||
os << "uint64_t (*fsel_d)(uint64_t v1, uint64_t v2, uint32_t op)=" << (uintptr_t)&fsel_d << ";\\n";
|
||||
os << "uint64_t (*fclass_d)(uint64_t v1 )=" << (uintptr_t)&fclass_d << ";\\n";
|
||||
os << "uint64_t (*fcvt_32_64)(uint32_t v1, uint32_t op, uint8_t mode)=" << (uintptr_t)&fcvt_32_64 << ";\\n";
|
||||
os << "uint32_t (*fcvt_64_32)(uint64_t v1, uint32_t op, uint8_t mode)=" << (uintptr_t)&fcvt_64_32 << ";\\n";
|
||||
os << "uint32_t (*unbox_s)(uint64_t v)=" << (uintptr_t)&unbox_s << ";\\n";
|
||||
<%}%>
|
||||
tu.add_prologue(os.str());
|
||||
}
|
||||
|
||||
} // namespace ${coreDef.name.toLowerCase()}
|
||||
|
||||
@ -323,22 +320,30 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
|
||||
} // namesapce tcc
|
||||
} // namespace iss
|
||||
|
||||
#include <iss/factory.h>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/riscv_hart_mu_p.h>
|
||||
#include <iss/factory.h>
|
||||
namespace iss {
|
||||
namespace {
|
||||
volatile std::array<bool, 2> dummy = {
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
}),
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{
|
||||
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
|
||||
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
|
||||
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
|
||||
if(init_data){
|
||||
auto* cb = reinterpret_cast<semihosting_cb_t<arch::traits<arch::${coreDef.name.toLowerCase()}>::reg_t>*>(init_data);
|
||||
cpu->set_semihosting_callback(*cb);
|
||||
}
|
||||
return {cpu_ptr{cpu}, vm_ptr{vm}};
|
||||
})
|
||||
};
|
||||
|
2
softfloat/.gitignore
vendored
Normal file
2
softfloat/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build/*/*.o
|
||||
build/*/*.a
|
@ -327,7 +327,7 @@ set(OTHERS
|
||||
|
||||
set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS})
|
||||
|
||||
add_library(softfloat ${LIB_SOURCES})
|
||||
add_library(softfloat STATIC ${LIB_SOURCES})
|
||||
set_property(TARGET softfloat PROPERTY C_STANDARD 99)
|
||||
target_compile_definitions(softfloat PRIVATE
|
||||
SOFTFLOAT_ROUND_ODD
|
||||
@ -347,7 +347,7 @@ set_target_properties(softfloat PROPERTIES
|
||||
|
||||
install(TARGETS softfloat
|
||||
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/static COMPONENT libs # static lib
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib
|
||||
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel # headers for mac (note the different component -> different package)
|
||||
|
24
softfloat/README.md
Normal file
24
softfloat/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
Package Overview for Berkeley SoftFloat Release 3e
|
||||
==================================================
|
||||
|
||||
John R. Hauser<br>
|
||||
2018 January 20
|
||||
|
||||
|
||||
Berkeley SoftFloat is a software implementation of binary floating-point
|
||||
that conforms to the IEEE Standard for Floating-Point Arithmetic. SoftFloat
|
||||
is distributed in the form of C source code. Building the SoftFloat sources
|
||||
generates a library file (typically `softfloat.a` or `libsoftfloat.a`)
|
||||
containing the floating-point subroutines.
|
||||
|
||||
|
||||
The SoftFloat package is documented in the following files in the `doc`
|
||||
subdirectory:
|
||||
|
||||
* [SoftFloat.html](http://www.jhauser.us/arithmetic/SoftFloat-3/doc/SoftFloat.html) Documentation for using the SoftFloat functions.
|
||||
* [SoftFloat-source.html](http://www.jhauser.us/arithmetic/SoftFloat-3/doc/SoftFloat-source.html) Documentation for building SoftFloat.
|
||||
* [SoftFloat-history.html](http://www.jhauser.us/arithmetic/SoftFloat-3/doc/SoftFloat-history.html) History of the major changes to SoftFloat.
|
||||
|
||||
Other files in the package comprise the source code for SoftFloat.
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
399
softfloat/build/Linux-RISCV64-GCC/Makefile
Normal file
399
softfloat/build/Linux-RISCV64-GCC/Makefile
Normal file
@ -0,0 +1,399 @@
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
# This Makefile is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
# Package, Release 3e, by John R. Hauser.
|
||||
#
|
||||
# Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the
|
||||
# University of California. 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 University 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 REGENTS 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 REGENTS 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.
|
||||
#
|
||||
#=============================================================================
|
||||
|
||||
SOURCE_DIR ?= ../../source
|
||||
SPECIALIZE_TYPE ?= RISCV
|
||||
MARCH ?= rv64gcv_zfh_zfhmin
|
||||
MABI ?= lp64d
|
||||
|
||||
SOFTFLOAT_OPTS ?= \
|
||||
-DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \
|
||||
-DSOFTFLOAT_FAST_DIV64TO32
|
||||
|
||||
DELETE = rm -f
|
||||
C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include
|
||||
COMPILE_C = \
|
||||
riscv64-unknown-linux-gnu-gcc -c -march=$(MARCH) -mabi=$(MABI) -Werror-implicit-function-declaration -DSOFTFLOAT_FAST_INT64 \
|
||||
$(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@
|
||||
MAKELIB = ar crs $@
|
||||
|
||||
OBJ = .o
|
||||
LIB = .a
|
||||
|
||||
OTHER_HEADERS = $(SOURCE_DIR)/include/opts-GCC.h
|
||||
|
||||
.PHONY: all
|
||||
all: softfloat$(LIB)
|
||||
|
||||
OBJS_PRIMITIVES = \
|
||||
s_eq128$(OBJ) \
|
||||
s_le128$(OBJ) \
|
||||
s_lt128$(OBJ) \
|
||||
s_shortShiftLeft128$(OBJ) \
|
||||
s_shortShiftRight128$(OBJ) \
|
||||
s_shortShiftRightJam64$(OBJ) \
|
||||
s_shortShiftRightJam64Extra$(OBJ) \
|
||||
s_shortShiftRightJam128$(OBJ) \
|
||||
s_shortShiftRightJam128Extra$(OBJ) \
|
||||
s_shiftRightJam32$(OBJ) \
|
||||
s_shiftRightJam64$(OBJ) \
|
||||
s_shiftRightJam64Extra$(OBJ) \
|
||||
s_shiftRightJam128$(OBJ) \
|
||||
s_shiftRightJam128Extra$(OBJ) \
|
||||
s_shiftRightJam256M$(OBJ) \
|
||||
s_countLeadingZeros8$(OBJ) \
|
||||
s_countLeadingZeros16$(OBJ) \
|
||||
s_countLeadingZeros32$(OBJ) \
|
||||
s_countLeadingZeros64$(OBJ) \
|
||||
s_add128$(OBJ) \
|
||||
s_add256M$(OBJ) \
|
||||
s_sub128$(OBJ) \
|
||||
s_sub256M$(OBJ) \
|
||||
s_mul64ByShifted32To128$(OBJ) \
|
||||
s_mul64To128$(OBJ) \
|
||||
s_mul128By32$(OBJ) \
|
||||
s_mul128To256M$(OBJ) \
|
||||
s_approxRecip_1Ks$(OBJ) \
|
||||
s_approxRecip32_1$(OBJ) \
|
||||
s_approxRecipSqrt_1Ks$(OBJ) \
|
||||
s_approxRecipSqrt32_1$(OBJ) \
|
||||
|
||||
OBJS_SPECIALIZE = \
|
||||
softfloat_raiseFlags$(OBJ) \
|
||||
s_f16UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF16UI$(OBJ) \
|
||||
s_propagateNaNF16UI$(OBJ) \
|
||||
s_bf16UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToBF16UI$(OBJ) \
|
||||
s_f32UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF32UI$(OBJ) \
|
||||
s_propagateNaNF32UI$(OBJ) \
|
||||
s_f64UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF64UI$(OBJ) \
|
||||
s_propagateNaNF64UI$(OBJ) \
|
||||
extF80M_isSignalingNaN$(OBJ) \
|
||||
s_extF80UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToExtF80UI$(OBJ) \
|
||||
s_propagateNaNExtF80UI$(OBJ) \
|
||||
f128M_isSignalingNaN$(OBJ) \
|
||||
s_f128UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF128UI$(OBJ) \
|
||||
s_propagateNaNF128UI$(OBJ) \
|
||||
|
||||
OBJS_OTHERS = \
|
||||
s_roundToUI32$(OBJ) \
|
||||
s_roundToUI64$(OBJ) \
|
||||
s_roundToI32$(OBJ) \
|
||||
s_roundToI64$(OBJ) \
|
||||
s_normSubnormalBF16Sig$(OBJ) \
|
||||
s_roundPackToBF16$(OBJ) \
|
||||
s_normSubnormalF16Sig$(OBJ) \
|
||||
s_roundPackToF16$(OBJ) \
|
||||
s_normRoundPackToF16$(OBJ) \
|
||||
s_addMagsF16$(OBJ) \
|
||||
s_subMagsF16$(OBJ) \
|
||||
s_mulAddF16$(OBJ) \
|
||||
s_normSubnormalF32Sig$(OBJ) \
|
||||
s_roundPackToF32$(OBJ) \
|
||||
s_normRoundPackToF32$(OBJ) \
|
||||
s_addMagsF32$(OBJ) \
|
||||
s_subMagsF32$(OBJ) \
|
||||
s_mulAddF32$(OBJ) \
|
||||
s_normSubnormalF64Sig$(OBJ) \
|
||||
s_roundPackToF64$(OBJ) \
|
||||
s_normRoundPackToF64$(OBJ) \
|
||||
s_addMagsF64$(OBJ) \
|
||||
s_subMagsF64$(OBJ) \
|
||||
s_mulAddF64$(OBJ) \
|
||||
s_normSubnormalExtF80Sig$(OBJ) \
|
||||
s_roundPackToExtF80$(OBJ) \
|
||||
s_normRoundPackToExtF80$(OBJ) \
|
||||
s_addMagsExtF80$(OBJ) \
|
||||
s_subMagsExtF80$(OBJ) \
|
||||
s_normSubnormalF128Sig$(OBJ) \
|
||||
s_roundPackToF128$(OBJ) \
|
||||
s_normRoundPackToF128$(OBJ) \
|
||||
s_addMagsF128$(OBJ) \
|
||||
s_subMagsF128$(OBJ) \
|
||||
s_mulAddF128$(OBJ) \
|
||||
softfloat_state$(OBJ) \
|
||||
ui32_to_f16$(OBJ) \
|
||||
ui32_to_f32$(OBJ) \
|
||||
ui32_to_f64$(OBJ) \
|
||||
ui32_to_extF80$(OBJ) \
|
||||
ui32_to_extF80M$(OBJ) \
|
||||
ui32_to_f128$(OBJ) \
|
||||
ui32_to_f128M$(OBJ) \
|
||||
ui64_to_f16$(OBJ) \
|
||||
ui64_to_f32$(OBJ) \
|
||||
ui64_to_f64$(OBJ) \
|
||||
ui64_to_extF80$(OBJ) \
|
||||
ui64_to_extF80M$(OBJ) \
|
||||
ui64_to_f128$(OBJ) \
|
||||
ui64_to_f128M$(OBJ) \
|
||||
i32_to_f16$(OBJ) \
|
||||
i32_to_f32$(OBJ) \
|
||||
i32_to_f64$(OBJ) \
|
||||
i32_to_extF80$(OBJ) \
|
||||
i32_to_extF80M$(OBJ) \
|
||||
i32_to_f128$(OBJ) \
|
||||
i32_to_f128M$(OBJ) \
|
||||
i64_to_f16$(OBJ) \
|
||||
i64_to_f32$(OBJ) \
|
||||
i64_to_f64$(OBJ) \
|
||||
i64_to_extF80$(OBJ) \
|
||||
i64_to_extF80M$(OBJ) \
|
||||
i64_to_f128$(OBJ) \
|
||||
i64_to_f128M$(OBJ) \
|
||||
bf16_isSignalingNaN$(OBJ) \
|
||||
bf16_to_f32$(OBJ) \
|
||||
f16_to_ui32$(OBJ) \
|
||||
f16_to_ui64$(OBJ) \
|
||||
f16_to_i32$(OBJ) \
|
||||
f16_to_i64$(OBJ) \
|
||||
f16_to_ui32_r_minMag$(OBJ) \
|
||||
f16_to_ui64_r_minMag$(OBJ) \
|
||||
f16_to_i32_r_minMag$(OBJ) \
|
||||
f16_to_i64_r_minMag$(OBJ) \
|
||||
f16_to_f32$(OBJ) \
|
||||
f16_to_f64$(OBJ) \
|
||||
f16_to_extF80$(OBJ) \
|
||||
f16_to_extF80M$(OBJ) \
|
||||
f16_to_f128$(OBJ) \
|
||||
f16_to_f128M$(OBJ) \
|
||||
f16_roundToInt$(OBJ) \
|
||||
f16_add$(OBJ) \
|
||||
f16_sub$(OBJ) \
|
||||
f16_mul$(OBJ) \
|
||||
f16_mulAdd$(OBJ) \
|
||||
f16_div$(OBJ) \
|
||||
f16_rem$(OBJ) \
|
||||
f16_sqrt$(OBJ) \
|
||||
f16_eq$(OBJ) \
|
||||
f16_le$(OBJ) \
|
||||
f16_lt$(OBJ) \
|
||||
f16_eq_signaling$(OBJ) \
|
||||
f16_le_quiet$(OBJ) \
|
||||
f16_lt_quiet$(OBJ) \
|
||||
f16_isSignalingNaN$(OBJ) \
|
||||
f32_to_ui32$(OBJ) \
|
||||
f32_to_ui64$(OBJ) \
|
||||
f32_to_i32$(OBJ) \
|
||||
f32_to_i64$(OBJ) \
|
||||
f32_to_ui32_r_minMag$(OBJ) \
|
||||
f32_to_ui64_r_minMag$(OBJ) \
|
||||
f32_to_i32_r_minMag$(OBJ) \
|
||||
f32_to_i64_r_minMag$(OBJ) \
|
||||
f32_to_bf16$(OBJ) \
|
||||
f32_to_f16$(OBJ) \
|
||||
f32_to_f64$(OBJ) \
|
||||
f32_to_extF80$(OBJ) \
|
||||
f32_to_extF80M$(OBJ) \
|
||||
f32_to_f128$(OBJ) \
|
||||
f32_to_f128M$(OBJ) \
|
||||
f32_roundToInt$(OBJ) \
|
||||
f32_add$(OBJ) \
|
||||
f32_sub$(OBJ) \
|
||||
f32_mul$(OBJ) \
|
||||
f32_mulAdd$(OBJ) \
|
||||
f32_div$(OBJ) \
|
||||
f32_rem$(OBJ) \
|
||||
f32_sqrt$(OBJ) \
|
||||
f32_eq$(OBJ) \
|
||||
f32_le$(OBJ) \
|
||||
f32_lt$(OBJ) \
|
||||
f32_eq_signaling$(OBJ) \
|
||||
f32_le_quiet$(OBJ) \
|
||||
f32_lt_quiet$(OBJ) \
|
||||
f32_isSignalingNaN$(OBJ) \
|
||||
f64_to_ui32$(OBJ) \
|
||||
f64_to_ui64$(OBJ) \
|
||||
f64_to_i32$(OBJ) \
|
||||
f64_to_i64$(OBJ) \
|
||||
f64_to_ui32_r_minMag$(OBJ) \
|
||||
f64_to_ui64_r_minMag$(OBJ) \
|
||||
f64_to_i32_r_minMag$(OBJ) \
|
||||
f64_to_i64_r_minMag$(OBJ) \
|
||||
f64_to_f16$(OBJ) \
|
||||
f64_to_f32$(OBJ) \
|
||||
f64_to_extF80$(OBJ) \
|
||||
f64_to_extF80M$(OBJ) \
|
||||
f64_to_f128$(OBJ) \
|
||||
f64_to_f128M$(OBJ) \
|
||||
f64_roundToInt$(OBJ) \
|
||||
f64_add$(OBJ) \
|
||||
f64_sub$(OBJ) \
|
||||
f64_mul$(OBJ) \
|
||||
f64_mulAdd$(OBJ) \
|
||||
f64_div$(OBJ) \
|
||||
f64_rem$(OBJ) \
|
||||
f64_sqrt$(OBJ) \
|
||||
f64_eq$(OBJ) \
|
||||
f64_le$(OBJ) \
|
||||
f64_lt$(OBJ) \
|
||||
f64_eq_signaling$(OBJ) \
|
||||
f64_le_quiet$(OBJ) \
|
||||
f64_lt_quiet$(OBJ) \
|
||||
f64_isSignalingNaN$(OBJ) \
|
||||
extF80_to_ui32$(OBJ) \
|
||||
extF80_to_ui64$(OBJ) \
|
||||
extF80_to_i32$(OBJ) \
|
||||
extF80_to_i64$(OBJ) \
|
||||
extF80_to_ui32_r_minMag$(OBJ) \
|
||||
extF80_to_ui64_r_minMag$(OBJ) \
|
||||
extF80_to_i32_r_minMag$(OBJ) \
|
||||
extF80_to_i64_r_minMag$(OBJ) \
|
||||
extF80_to_f16$(OBJ) \
|
||||
extF80_to_f32$(OBJ) \
|
||||
extF80_to_f64$(OBJ) \
|
||||
extF80_to_f128$(OBJ) \
|
||||
extF80_roundToInt$(OBJ) \
|
||||
extF80_add$(OBJ) \
|
||||
extF80_sub$(OBJ) \
|
||||
extF80_mul$(OBJ) \
|
||||
extF80_div$(OBJ) \
|
||||
extF80_rem$(OBJ) \
|
||||
extF80_sqrt$(OBJ) \
|
||||
extF80_eq$(OBJ) \
|
||||
extF80_le$(OBJ) \
|
||||
extF80_lt$(OBJ) \
|
||||
extF80_eq_signaling$(OBJ) \
|
||||
extF80_le_quiet$(OBJ) \
|
||||
extF80_lt_quiet$(OBJ) \
|
||||
extF80_isSignalingNaN$(OBJ) \
|
||||
extF80M_to_ui32$(OBJ) \
|
||||
extF80M_to_ui64$(OBJ) \
|
||||
extF80M_to_i32$(OBJ) \
|
||||
extF80M_to_i64$(OBJ) \
|
||||
extF80M_to_ui32_r_minMag$(OBJ) \
|
||||
extF80M_to_ui64_r_minMag$(OBJ) \
|
||||
extF80M_to_i32_r_minMag$(OBJ) \
|
||||
extF80M_to_i64_r_minMag$(OBJ) \
|
||||
extF80M_to_f16$(OBJ) \
|
||||
extF80M_to_f32$(OBJ) \
|
||||
extF80M_to_f64$(OBJ) \
|
||||
extF80M_to_f128M$(OBJ) \
|
||||
extF80M_roundToInt$(OBJ) \
|
||||
extF80M_add$(OBJ) \
|
||||
extF80M_sub$(OBJ) \
|
||||
extF80M_mul$(OBJ) \
|
||||
extF80M_div$(OBJ) \
|
||||
extF80M_rem$(OBJ) \
|
||||
extF80M_sqrt$(OBJ) \
|
||||
extF80M_eq$(OBJ) \
|
||||
extF80M_le$(OBJ) \
|
||||
extF80M_lt$(OBJ) \
|
||||
extF80M_eq_signaling$(OBJ) \
|
||||
extF80M_le_quiet$(OBJ) \
|
||||
extF80M_lt_quiet$(OBJ) \
|
||||
f128_to_ui32$(OBJ) \
|
||||
f128_to_ui64$(OBJ) \
|
||||
f128_to_i32$(OBJ) \
|
||||
f128_to_i64$(OBJ) \
|
||||
f128_to_ui32_r_minMag$(OBJ) \
|
||||
f128_to_ui64_r_minMag$(OBJ) \
|
||||
f128_to_i32_r_minMag$(OBJ) \
|
||||
f128_to_i64_r_minMag$(OBJ) \
|
||||
f128_to_f16$(OBJ) \
|
||||
f128_to_f32$(OBJ) \
|
||||
f128_to_extF80$(OBJ) \
|
||||
f128_to_f64$(OBJ) \
|
||||
f128_roundToInt$(OBJ) \
|
||||
f128_add$(OBJ) \
|
||||
f128_sub$(OBJ) \
|
||||
f128_mul$(OBJ) \
|
||||
f128_mulAdd$(OBJ) \
|
||||
f128_div$(OBJ) \
|
||||
f128_rem$(OBJ) \
|
||||
f128_sqrt$(OBJ) \
|
||||
f128_eq$(OBJ) \
|
||||
f128_le$(OBJ) \
|
||||
f128_lt$(OBJ) \
|
||||
f128_eq_signaling$(OBJ) \
|
||||
f128_le_quiet$(OBJ) \
|
||||
f128_lt_quiet$(OBJ) \
|
||||
f128_isSignalingNaN$(OBJ) \
|
||||
f128M_to_ui32$(OBJ) \
|
||||
f128M_to_ui64$(OBJ) \
|
||||
f128M_to_i32$(OBJ) \
|
||||
f128M_to_i64$(OBJ) \
|
||||
f128M_to_ui32_r_minMag$(OBJ) \
|
||||
f128M_to_ui64_r_minMag$(OBJ) \
|
||||
f128M_to_i32_r_minMag$(OBJ) \
|
||||
f128M_to_i64_r_minMag$(OBJ) \
|
||||
f128M_to_f16$(OBJ) \
|
||||
f128M_to_f32$(OBJ) \
|
||||
f128M_to_extF80M$(OBJ) \
|
||||
f128M_to_f64$(OBJ) \
|
||||
f128M_roundToInt$(OBJ) \
|
||||
f128M_add$(OBJ) \
|
||||
f128M_sub$(OBJ) \
|
||||
f128M_mul$(OBJ) \
|
||||
f128M_mulAdd$(OBJ) \
|
||||
f128M_div$(OBJ) \
|
||||
f128M_rem$(OBJ) \
|
||||
f128M_sqrt$(OBJ) \
|
||||
f128M_eq$(OBJ) \
|
||||
f128M_le$(OBJ) \
|
||||
f128M_lt$(OBJ) \
|
||||
f128M_eq_signaling$(OBJ) \
|
||||
f128M_le_quiet$(OBJ) \
|
||||
f128M_lt_quiet$(OBJ) \
|
||||
|
||||
OBJS_ALL = $(OBJS_PRIMITIVES) $(OBJS_SPECIALIZE) $(OBJS_OTHERS)
|
||||
|
||||
$(OBJS_ALL): \
|
||||
$(OTHER_HEADERS) platform.h $(SOURCE_DIR)/include/primitiveTypes.h \
|
||||
$(SOURCE_DIR)/include/primitives.h
|
||||
$(OBJS_SPECIALIZE) $(OBJS_OTHERS): \
|
||||
$(SOURCE_DIR)/include/softfloat_types.h $(SOURCE_DIR)/include/internals.h \
|
||||
$(SOURCE_DIR)/$(SPECIALIZE_TYPE)/specialize.h \
|
||||
$(SOURCE_DIR)/include/softfloat.h
|
||||
|
||||
$(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c
|
||||
$(COMPILE_C) $(SOURCE_DIR)/$*.c
|
||||
|
||||
$(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c
|
||||
$(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c
|
||||
|
||||
softfloat$(LIB): $(OBJS_ALL)
|
||||
$(DELETE) $@
|
||||
$(MAKELIB) $^
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(DELETE) $(OBJS_ALL) softfloat$(LIB)
|
||||
|
54
softfloat/build/Linux-RISCV64-GCC/platform.h
Normal file
54
softfloat/build/Linux-RISCV64-GCC/platform.h
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the
|
||||
University of California. 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 University 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 REGENTS 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 REGENTS 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.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
#define INLINE extern inline
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#define SOFTFLOAT_INTRINSIC_INT128 1
|
||||
#include "opts-GCC.h"
|
||||
|
@ -94,6 +94,8 @@ OBJS_SPECIALIZE = \
|
||||
s_f16UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF16UI$(OBJ) \
|
||||
s_propagateNaNF16UI$(OBJ) \
|
||||
s_bf16UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToBF16UI$(OBJ) \
|
||||
s_f32UIToCommonNaN$(OBJ) \
|
||||
s_commonNaNToF32UI$(OBJ) \
|
||||
s_propagateNaNF32UI$(OBJ) \
|
||||
@ -114,6 +116,8 @@ OBJS_OTHERS = \
|
||||
s_roundToUI64$(OBJ) \
|
||||
s_roundToI32$(OBJ) \
|
||||
s_roundToI64$(OBJ) \
|
||||
s_normSubnormalBF16Sig$(OBJ) \
|
||||
s_roundPackToBF16$(OBJ) \
|
||||
s_normSubnormalF16Sig$(OBJ) \
|
||||
s_roundPackToF16$(OBJ) \
|
||||
s_normRoundPackToF16$(OBJ) \
|
||||
@ -172,6 +176,8 @@ OBJS_OTHERS = \
|
||||
i64_to_extF80M$(OBJ) \
|
||||
i64_to_f128$(OBJ) \
|
||||
i64_to_f128M$(OBJ) \
|
||||
bf16_isSignalingNaN$(OBJ) \
|
||||
bf16_to_f32$(OBJ) \
|
||||
f16_to_ui32$(OBJ) \
|
||||
f16_to_ui64$(OBJ) \
|
||||
f16_to_i32$(OBJ) \
|
||||
@ -209,6 +215,7 @@ OBJS_OTHERS = \
|
||||
f32_to_ui64_r_minMag$(OBJ) \
|
||||
f32_to_i32_r_minMag$(OBJ) \
|
||||
f32_to_i64_r_minMag$(OBJ) \
|
||||
f32_to_bf16$(OBJ) \
|
||||
f32_to_f16$(OBJ) \
|
||||
f32_to_f64$(OBJ) \
|
||||
f32_to_extF80$(OBJ) \
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,6 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
@ -35,11 +35,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __GNUC_STDC_INLINE__
|
||||
#define INLINE inline
|
||||
#else
|
||||
@ -47,7 +47,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SOFTFLOAT_BUILTIN_CLZ 1
|
||||
#define SOFTFLOAT_INTRINSIC_INT128 1
|
||||
#include "opts-GCC.h"
|
||||
|
||||
|
@ -115,6 +115,8 @@ OBJS_OTHERS = \
|
||||
s_roundToUI64$(OBJ) \
|
||||
s_roundToI32$(OBJ) \
|
||||
s_roundToI64$(OBJ) \
|
||||
s_normSubnormalBF16Sig$(OBJ) \
|
||||
s_roundPackToBF16$(OBJ) \
|
||||
s_normSubnormalF16Sig$(OBJ) \
|
||||
s_roundPackToF16$(OBJ) \
|
||||
s_normRoundPackToF16$(OBJ) \
|
||||
@ -173,6 +175,8 @@ OBJS_OTHERS = \
|
||||
i64_to_extF80M$(OBJ) \
|
||||
i64_to_f128$(OBJ) \
|
||||
i64_to_f128M$(OBJ) \
|
||||
bf16_isSignalingNaN$(OBJ) \
|
||||
bf16_to_f32$(OBJ) \
|
||||
f16_to_ui32$(OBJ) \
|
||||
f16_to_ui64$(OBJ) \
|
||||
f16_to_i32$(OBJ) \
|
||||
@ -210,6 +214,7 @@ OBJS_OTHERS = \
|
||||
f32_to_ui64_r_minMag$(OBJ) \
|
||||
f32_to_i32_r_minMag$(OBJ) \
|
||||
f32_to_i64_r_minMag$(OBJ) \
|
||||
f32_to_bf16$(OBJ) \
|
||||
f32_to_f16$(OBJ) \
|
||||
f32_to_f64$(OBJ) \
|
||||
f32_to_extF80$(OBJ) \
|
||||
|
@ -37,13 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Edit lines marked with `==>'. See "SoftFloat-source.html".
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define LITTLEENDIAN 1
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define INLINE inline
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define INLINE inline
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define THREAD_LOCAL _Thread_local
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define THREAD_LOCAL _Thread_local
|
||||
|
@ -37,13 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Edit lines marked with `==>'. See "SoftFloat-source.html".
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define LITTLEENDIAN 1
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define LITTLEENDIAN 1
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define INLINE inline
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define INLINE inline
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
==> #define THREAD_LOCAL _Thread_local
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
== > #define THREAD_LOCAL _Thread_local
|
||||
|
@ -508,7 +508,7 @@ significant extra cost.
|
||||
On computers where the word size is <NOBR>64 bits</NOBR> or larger, both
|
||||
function versions (<CODE>f128M_add</CODE> and <CODE>f128_add</CODE>) are
|
||||
provided, because the cost of passing by value is then more reasonable.
|
||||
Applications that must be portable accross both classes of computers must use
|
||||
Applications that must be portable across both classes of computers must use
|
||||
the pointer-based functions, as these are always implemented.
|
||||
However, if it is known that SoftFloat includes the by-value functions for all
|
||||
platforms of interest, programmers can use whichever version they prefer.
|
||||
|
59
softfloat/source/8086-SSE/s_bf16UIToCommonNaN.c
Normal file
59
softfloat/source/8086-SSE/s_bf16UIToCommonNaN.c
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming `uiA' has the bit pattern of a BF16 NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_bf16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( softfloat_isSigNaNBF16UI( uiA ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = uiA>>15;
|
||||
zPtr->v64 = (uint_fast64_t) uiA<<56;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
51
softfloat/source/8086-SSE/s_commonNaNToBF16UI.c
Normal file
51
softfloat/source/8086-SSE/s_commonNaNToBF16UI.c
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by `aPtr' into a BF16 NaN, and
|
||||
| returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_commonNaNToBF16UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
|
||||
return (uint_fast16_t) aPtr->sign<<15 | 0x7FC0 | aPtr->v64>>56;
|
||||
|
||||
}
|
||||
|
@ -116,6 +116,27 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a
|
||||
| 16-bit brain floating-point (BF16) signaling NaN.
|
||||
| Note: This macro evaluates its argument more than once.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define softfloat_isSigNaNBF16UI(uiA) ((((uiA)&0x7FC0) == 0x7F80) && ((uiA)&0x003F))
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming 'uiA' has the bit pattern of a 16-bit BF16 floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_bf16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_commonNaNToBF16UI(const struct commonNaN* aPtr);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 32-bit floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
5
softfloat/source/RISCV/s_bf16UIToCommonNaN.c
Normal file
5
softfloat/source/RISCV/s_bf16UIToCommonNaN.c
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
5
softfloat/source/RISCV/s_commonNaNToBF16UI.c
Normal file
5
softfloat/source/RISCV/s_commonNaNToBF16UI.c
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,9 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "softfloat_types.h"
|
||||
|
||||
#define softfloat_commonNaNToExtF80M softfloat_commonNaNToExtF80M
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -49,8 +50,8 @@ void
|
||||
const struct commonNaN *aPtr, struct extFloat80M *zSPtr )
|
||||
{
|
||||
|
||||
zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF );
|
||||
zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1;
|
||||
zSPtr->signExp = defaultNaNExtF80UI64;
|
||||
zSPtr->signif = defaultNaNExtF80UI0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,9 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "primitives.h"
|
||||
#include "primitiveTypes.h"
|
||||
|
||||
#define softfloat_commonNaNToExtF80UI softfloat_commonNaNToExtF80UI
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -48,8 +49,8 @@ struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
struct uint128 uiZ;
|
||||
|
||||
uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF;
|
||||
uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1;
|
||||
uiZ.v64 = defaultNaNExtF80UI64;
|
||||
uiZ.v0 = defaultNaNExtF80UI0;
|
||||
return uiZ;
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -36,7 +36,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "primitives.h"
|
||||
#include "primitiveTypes.h"
|
||||
|
||||
#define softfloat_commonNaNToF128M softfloat_commonNaNToF128M
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -49,8 +51,10 @@ void
|
||||
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr )
|
||||
{
|
||||
|
||||
softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr );
|
||||
zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000;
|
||||
zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96;
|
||||
zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64;
|
||||
zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32;
|
||||
zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,9 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "primitives.h"
|
||||
#include "primitiveTypes.h"
|
||||
|
||||
#define softfloat_commonNaNToF128UI softfloat_commonNaNToF128UI
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -47,8 +48,8 @@ struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
struct uint128 uiZ;
|
||||
|
||||
uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 );
|
||||
uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 );
|
||||
uiZ.v64 = defaultNaNF128UI64;
|
||||
uiZ.v0 = defaultNaNF128UI0;
|
||||
return uiZ;
|
||||
|
||||
}
|
||||
|
@ -1,51 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
|
||||
return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,51 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
|
||||
return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,53 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr )
|
||||
{
|
||||
|
||||
return
|
||||
(uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 )
|
||||
| aPtr->v64>>12;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,62 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is
|
||||
| a NaN, converts this NaN to the common NaN form, and stores the resulting
|
||||
| common NaN at the location pointed to by `zPtr'. If the NaN is a signaling
|
||||
| NaN, the invalid exception is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
softfloat_extF80MToCommonNaN(
|
||||
const struct extFloat80M *aSPtr, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = signExtF80UI64( aSPtr->signExp );
|
||||
zPtr->v64 = aSPtr->signif<<1;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,62 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0'
|
||||
| has the bit pattern of an 80-bit extended floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
softfloat_extF80UIToCommonNaN(
|
||||
uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = uiA64>>15;
|
||||
zPtr->v64 = uiA0<<1;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,62 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "primitives.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN,
|
||||
| converts this NaN to the common NaN form, and stores the resulting common
|
||||
| NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN,
|
||||
| the invalid exception is raised. Argument `aWPtr' points to an array of
|
||||
| four 32-bit elements that concatenate in the platform's normal endian order
|
||||
| to form a 128-bit floating-point value.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = aWPtr[indexWordHi( 4 )]>>31;
|
||||
softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,65 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "primitives.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0'
|
||||
| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to
|
||||
| the common NaN form, and stores the resulting common NaN at the location
|
||||
| pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception
|
||||
| is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
softfloat_f128UIToCommonNaN(
|
||||
uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr )
|
||||
{
|
||||
struct uint128 NaNSig;
|
||||
|
||||
if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 );
|
||||
zPtr->sign = uiA64>>63;
|
||||
zPtr->v64 = NaNSig.v64;
|
||||
zPtr->v0 = NaNSig.v0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,59 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( softfloat_isSigNaNF16UI( uiA ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = uiA>>15;
|
||||
zPtr->v64 = (uint_fast64_t) uiA<<54;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,59 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( softfloat_isSigNaNF32UI( uiA ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = uiA>>31;
|
||||
zPtr->v64 = (uint_fast64_t) uiA<<41;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,59 +1,5 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
| This file intentionally contains no code.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr )
|
||||
{
|
||||
|
||||
if ( softfloat_isSigNaNF64UI( uiA ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
}
|
||||
zPtr->sign = uiA>>63;
|
||||
zPtr->v64 = uiA<<12;
|
||||
zPtr->v0 = 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,10 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "primitiveTypes.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
@ -54,54 +53,22 @@ void
|
||||
struct extFloat80M *zSPtr
|
||||
)
|
||||
{
|
||||
bool isSigNaNA;
|
||||
const struct extFloat80M *sPtr;
|
||||
bool isSigNaNB;
|
||||
uint_fast16_t uiB64;
|
||||
uint64_t uiB0;
|
||||
uint_fast16_t uiA64;
|
||||
uint64_t uiA0;
|
||||
uint_fast16_t uiMagA64, uiMagB64;
|
||||
uint_fast16_t ui64;
|
||||
uint_fast64_t ui0;
|
||||
|
||||
isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr );
|
||||
sPtr = aSPtr;
|
||||
if ( ! bSPtr ) {
|
||||
if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
goto copy;
|
||||
}
|
||||
isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr );
|
||||
if ( isSigNaNA | isSigNaNB ) {
|
||||
ui64 = aSPtr->signExp;
|
||||
ui0 = aSPtr->signif;
|
||||
if (
|
||||
softfloat_isSigNaNExtF80UI( ui64, ui0 )
|
||||
|| (bSPtr
|
||||
&& (ui64 = bSPtr->signExp,
|
||||
ui0 = bSPtr->signif,
|
||||
softfloat_isSigNaNExtF80UI( ui64, ui0 )))
|
||||
) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) {
|
||||
uiB64 = bSPtr->signExp;
|
||||
if ( isSigNaNB ) goto returnLargerUIMag;
|
||||
uiB0 = bSPtr->signif;
|
||||
if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto copyB;
|
||||
goto copy;
|
||||
} else {
|
||||
uiA64 = aSPtr->signExp;
|
||||
uiA0 = aSPtr->signif;
|
||||
if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto copy;
|
||||
goto copyB;
|
||||
}
|
||||
}
|
||||
uiB64 = bSPtr->signExp;
|
||||
returnLargerUIMag:
|
||||
uiA64 = aSPtr->signExp;
|
||||
uiMagA64 = uiA64 & 0x7FFF;
|
||||
uiMagB64 = uiB64 & 0x7FFF;
|
||||
if ( uiMagA64 < uiMagB64 ) goto copyB;
|
||||
if ( uiMagB64 < uiMagA64 ) goto copy;
|
||||
uiA0 = aSPtr->signif;
|
||||
uiB0 = bSPtr->signif;
|
||||
if ( uiA0 < uiB0 ) goto copyB;
|
||||
if ( uiB0 < uiA0 ) goto copy;
|
||||
if ( uiA64 < uiB64 ) goto copy;
|
||||
copyB:
|
||||
sPtr = bSPtr;
|
||||
copy:
|
||||
zSPtr->signExp = sPtr->signExp;
|
||||
zSPtr->signif = sPtr->signif | UINT64_C( 0xC000000000000000 );
|
||||
zSPtr->signExp = defaultNaNExtF80UI64;
|
||||
zSPtr->signif = defaultNaNExtF80UI0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -34,17 +34,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "primitiveTypes.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting the unsigned integer formed from concatenating 'uiA64' and
|
||||
| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting
|
||||
| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another
|
||||
| Interpreting the unsigned integer formed from concatenating `uiA64' and
|
||||
| `uiA0' as an 80-bit extended floating-point value, and likewise interpreting
|
||||
| the unsigned integer formed from concatenating `uiB64' and `uiB0' as another
|
||||
| 80-bit extended floating-point value, and assuming at least on of these
|
||||
| floating-point values is a NaN, returns the bit pattern of the combined NaN
|
||||
| result. If either original floating-point value is a signaling NaN, the
|
||||
@ -58,48 +57,16 @@ struct uint128
|
||||
uint_fast64_t uiB0
|
||||
)
|
||||
{
|
||||
bool isSigNaNA, isSigNaNB;
|
||||
uint_fast64_t uiNonsigA0, uiNonsigB0;
|
||||
uint_fast16_t uiMagA64, uiMagB64;
|
||||
struct uint128 uiZ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 );
|
||||
isSigNaNB = softfloat_isSigNaNExtF80UI( uiB64, uiB0 );
|
||||
/*------------------------------------------------------------------------
|
||||
| Make NaNs non-signaling.
|
||||
*------------------------------------------------------------------------*/
|
||||
uiNonsigA0 = uiA0 | UINT64_C( 0xC000000000000000 );
|
||||
uiNonsigB0 = uiB0 | UINT64_C( 0xC000000000000000 );
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
if ( isSigNaNA | isSigNaNB ) {
|
||||
if (
|
||||
softfloat_isSigNaNExtF80UI( uiA64, uiA0 )
|
||||
|| softfloat_isSigNaNExtF80UI( uiB64, uiB0 )
|
||||
) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) {
|
||||
if ( isSigNaNB ) goto returnLargerMag;
|
||||
if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto returnB;
|
||||
goto returnA;
|
||||
} else {
|
||||
if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto returnA;
|
||||
goto returnB;
|
||||
}
|
||||
}
|
||||
returnLargerMag:
|
||||
uiMagA64 = uiA64 & 0x7FFF;
|
||||
uiMagB64 = uiB64 & 0x7FFF;
|
||||
if ( uiMagA64 < uiMagB64 ) goto returnB;
|
||||
if ( uiMagB64 < uiMagA64 ) goto returnA;
|
||||
if ( uiA0 < uiB0 ) goto returnB;
|
||||
if ( uiB0 < uiA0 ) goto returnA;
|
||||
if ( uiA64 < uiB64 ) goto returnA;
|
||||
returnB:
|
||||
uiZ.v64 = uiB64;
|
||||
uiZ.v0 = uiNonsigB0;
|
||||
return uiZ;
|
||||
returnA:
|
||||
uiZ.v64 = uiA64;
|
||||
uiZ.v0 = uiNonsigA0;
|
||||
uiZ.v64 = defaultNaNExtF80UI64;
|
||||
uiZ.v0 = defaultNaNExtF80UI0;
|
||||
return uiZ;
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2018 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,43 +34,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "primitiveTypes.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming at least one of the two 128-bit floating-point values pointed to by
|
||||
| `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location
|
||||
| pointed to by `zWPtr'. If either original floating-point value is a
|
||||
| signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr',
|
||||
| and `zWPtr' points to an array of four 32-bit elements that concatenate in
|
||||
| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location
|
||||
| pointed to by 'zWPtr'. If either original floating-point value is a
|
||||
| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr',
|
||||
| and 'zWPtr' points to an array of four 32-bit elements that concatenate in
|
||||
| the platform's normal endian order to form a 128-bit floating-point value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
softfloat_propagateNaNF128M(
|
||||
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr )
|
||||
{
|
||||
bool isSigNaNA;
|
||||
const uint32_t *ptr;
|
||||
|
||||
ptr = aWPtr;
|
||||
isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr );
|
||||
if (
|
||||
isSigNaNA
|
||||
f128M_isSignalingNaN( (const float128_t *) aWPtr )
|
||||
|| (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr ))
|
||||
) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) goto copy;
|
||||
}
|
||||
if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr;
|
||||
copy:
|
||||
zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000;
|
||||
zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )];
|
||||
zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )];
|
||||
zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )];
|
||||
zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96;
|
||||
zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64;
|
||||
zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32;
|
||||
zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,10 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "primitiveTypes.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
@ -58,23 +57,16 @@ struct uint128
|
||||
uint_fast64_t uiB0
|
||||
)
|
||||
{
|
||||
bool isSigNaNA;
|
||||
struct uint128 uiZ;
|
||||
|
||||
isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 );
|
||||
if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) {
|
||||
if (
|
||||
softfloat_isSigNaNF128UI( uiA64, uiA0 )
|
||||
|| softfloat_isSigNaNF128UI( uiB64, uiB0 )
|
||||
) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) goto returnNonsigA;
|
||||
}
|
||||
if ( isNaNF128UI( uiA64, uiA0 ) ) {
|
||||
returnNonsigA:
|
||||
uiZ.v64 = uiA64;
|
||||
uiZ.v0 = uiA0;
|
||||
} else {
|
||||
uiZ.v64 = uiB64;
|
||||
uiZ.v0 = uiB0;
|
||||
}
|
||||
uiZ.v64 |= UINT64_C( 0x0000800000000000 );
|
||||
uiZ.v64 = defaultNaNF128UI64;
|
||||
uiZ.v0 = defaultNaNF128UI0;
|
||||
return uiZ;
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -34,10 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
@ -50,14 +48,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
uint_fast16_t
|
||||
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB )
|
||||
{
|
||||
bool isSigNaNA;
|
||||
|
||||
isSigNaNA = softfloat_isSigNaNF16UI( uiA );
|
||||
if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) {
|
||||
if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) return uiA | 0x0200;
|
||||
}
|
||||
return (isNaNF16UI( uiA ) ? uiA : uiB) | 0x0200;
|
||||
return defaultNaNF16UI;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,10 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
@ -50,14 +48,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
uint_fast32_t
|
||||
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB )
|
||||
{
|
||||
bool isSigNaNA;
|
||||
|
||||
isSigNaNA = softfloat_isSigNaNF32UI( uiA );
|
||||
if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) {
|
||||
if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) return uiA | 0x00400000;
|
||||
}
|
||||
return (isNaNF32UI( uiA ) ? uiA : uiB) | 0x00400000;
|
||||
return defaultNaNF32UI;
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -34,10 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
@ -50,14 +48,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
uint_fast64_t
|
||||
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB )
|
||||
{
|
||||
bool isSigNaNA;
|
||||
|
||||
isSigNaNA = softfloat_isSigNaNF64UI( uiA );
|
||||
if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) {
|
||||
if ( softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) ) {
|
||||
softfloat_raiseFlags( softfloat_flag_invalid );
|
||||
if ( isSigNaNA ) return uiA | UINT64_C( 0x0008000000000000 );
|
||||
}
|
||||
return (isNaNF64UI( uiA ) ? uiA : uiB) | UINT64_C( 0x0008000000000000 );
|
||||
return defaultNaNF64UI;
|
||||
|
||||
}
|
||||
|
||||
|
@ -51,19 +51,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
| The values to return on conversions to 32-bit integer formats that raise an
|
||||
| invalid exception.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define ui32_fromPosOverflow UINT32_C(0xFFFFFFFF)
|
||||
#define ui32_fromNegOverflow UINT32_C(0x0)
|
||||
#define ui32_fromNaN UINT32_C(0xFFFFFFFF)
|
||||
#define i32_fromPosOverflow INT64_C(0x7FFFFFFF)
|
||||
#define i32_fromNegOverflow (-INT64_C(0x7FFFFFFF) - 1)
|
||||
#define i32_fromNaN INT64_C(0x7FFFFFFF)
|
||||
#define ui32_fromPosOverflow 0xFFFFFFFF
|
||||
#define ui32_fromNegOverflow 0
|
||||
#define ui32_fromNaN 0xFFFFFFFF
|
||||
#define i32_fromPosOverflow 0x7FFFFFFF
|
||||
#define i32_fromNegOverflow (-0x7FFFFFFF - 1)
|
||||
#define i32_fromNaN 0x7FFFFFFF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The values to return on conversions to 64-bit integer formats that raise an
|
||||
| invalid exception.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF)
|
||||
#define ui64_fromNegOverflow UINT64_C(0x0)
|
||||
#define ui64_fromNegOverflow 0
|
||||
#define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF)
|
||||
#define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF)
|
||||
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1)
|
||||
@ -74,18 +74,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
| to another.
|
||||
*----------------------------------------------------------------------------*/
|
||||
struct commonNaN {
|
||||
bool sign;
|
||||
#ifdef LITTLEENDIAN
|
||||
uint64_t v0, v64;
|
||||
#else
|
||||
uint64_t v64, v0;
|
||||
#endif
|
||||
char _unused;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 16-bit floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define defaultNaNF16UI 0xFE00
|
||||
#define defaultNaNF16UI 0x7E00
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a
|
||||
@ -94,19 +89,38 @@ struct commonNaN {
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF))
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a
|
||||
| 16-bit brain floating-point (BF16) signaling NaN.
|
||||
| Note: This macro evaluates its argument more than once.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define softfloat_isSigNaNBF16UI(uiA) ((((uiA)&0x7FC0) == 0x7F80) && ((uiA)&0x003F))
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* zPtr);
|
||||
#define softfloat_f16UIToCommonNaN(uiA, zPtr) \
|
||||
if(!((uiA)&0x0200)) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming 'uiA' has the bit pattern of a 16-bit BF16 floating-point NaN, converts
|
||||
| this NaN to the common NaN form, and stores the resulting common NaN at the
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define softfloat_bf16UIToCommonNaN(uiA, zPtr) \
|
||||
if(!((uiA)&0x0040)) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
|
||||
#define softfloat_commonNaNToF16UI(aPtr) ((uint_fast16_t)defaultNaNF16UI)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
|
||||
@ -116,6 +130,17 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 16-bit BF16 floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define defaultNaNBF16UI 0x7FC0
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define softfloat_commonNaNToBF16UI(aPtr) ((uint_fast16_t)defaultNaNBF16UI)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 32-bit floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
@ -134,13 +159,15 @@ uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB);
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr);
|
||||
#define softfloat_f32UIToCommonNaN(uiA, zPtr) \
|
||||
if(!((uiA)&0x00400000)) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
|
||||
#define softfloat_commonNaNToF32UI(aPtr) ((uint_fast32_t)defaultNaNF32UI)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
|
||||
@ -169,13 +196,15 @@ uint_fast32_t softfloat_propagateNaNF32UI(uint_fast32_t uiA, uint_fast32_t uiB);
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* zPtr);
|
||||
#define softfloat_f64UIToCommonNaN(uiA, zPtr) \
|
||||
if(!((uiA)&UINT64_C(0x0008000000000000))) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
|
||||
#define softfloat_commonNaNToF64UI(aPtr) ((uint_fast64_t)defaultNaNF64UI)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
|
||||
@ -188,7 +217,7 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 80-bit extended floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define defaultNaNExtF80UI64 0xFFFF
|
||||
#define defaultNaNExtF80UI64 0x7FFF
|
||||
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -214,14 +243,26 @@ uint_fast64_t softfloat_propagateNaNF64UI(uint_fast64_t uiA, uint_fast64_t uiB);
|
||||
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr);
|
||||
#define softfloat_extF80UIToCommonNaN(uiA64, uiA0, zPtr) \
|
||||
if(!((uiA0)&UINT64_C(0x4000000000000000))) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
|
||||
| floating-point NaN, and returns the bit pattern of this value as an unsigned
|
||||
| integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined INLINE && !defined softfloat_commonNaNToExtF80UI
|
||||
INLINE
|
||||
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr) {
|
||||
struct uint128 uiZ;
|
||||
uiZ.v64 = defaultNaNExtF80UI64;
|
||||
uiZ.v0 = defaultNaNExtF80UI0;
|
||||
return uiZ;
|
||||
}
|
||||
#else
|
||||
struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting the unsigned integer formed from concatenating 'uiA64' and
|
||||
@ -237,7 +278,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 128-bit floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define defaultNaNF128UI64 UINT64_C(0xFFFF800000000000)
|
||||
#define defaultNaNF128UI64 UINT64_C(0x7FFF800000000000)
|
||||
#define defaultNaNF128UI0 UINT64_C(0)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -256,13 +297,25 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
|
||||
| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
|
||||
| is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr);
|
||||
#define softfloat_f128UIToCommonNaN(uiA64, uiA0, zPtr) \
|
||||
if(!((uiA64)&UINT64_C(0x0000800000000000))) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
|
||||
| NaN, and returns the bit pattern of this value as an unsigned integer.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined INLINE && !defined softfloat_commonNaNToF128UI
|
||||
INLINE
|
||||
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN* aPtr) {
|
||||
struct uint128 uiZ;
|
||||
uiZ.v64 = defaultNaNF128UI64;
|
||||
uiZ.v0 = defaultNaNF128UI0;
|
||||
return uiZ;
|
||||
}
|
||||
#else
|
||||
struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Interpreting the unsigned integer formed from concatenating 'uiA64' and
|
||||
@ -288,14 +341,24 @@ struct uint128 softfloat_propagateNaNF128UI(uint_fast64_t uiA64, uint_fast64_t u
|
||||
| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
|
||||
| NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* zPtr);
|
||||
#define softfloat_extF80MToCommonNaN(aSPtr, zPtr) \
|
||||
if(!((aSPtr)->signif & UINT64_C(0x4000000000000000))) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended
|
||||
| floating-point NaN, and stores this NaN at the location pointed to by
|
||||
| 'zSPtr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined INLINE && !defined softfloat_commonNaNToExtF80M
|
||||
INLINE
|
||||
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr) {
|
||||
zSPtr->signExp = defaultNaNExtF80UI64;
|
||||
zSPtr->signif = defaultNaNExtF80UI0;
|
||||
}
|
||||
#else
|
||||
void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr);
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming at least one of the two 80-bit extended floating-point values
|
||||
@ -308,7 +371,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
|
||||
/*----------------------------------------------------------------------------
|
||||
| The bit pattern for a default generated 128-bit floating-point NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define defaultNaNF128UI96 0xFFFF8000
|
||||
#define defaultNaNF128UI96 0x7FFF8000
|
||||
#define defaultNaNF128UI64 0
|
||||
#define defaultNaNF128UI32 0
|
||||
#define defaultNaNF128UI0 0
|
||||
@ -321,7 +384,9 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
|
||||
| four 32-bit elements that concatenate in the platform's normal endian order
|
||||
| to form a 128-bit floating-point value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
|
||||
#define softfloat_f128MToCommonNaN(aWPtr, zPtr) \
|
||||
if(!((aWPtr)[indexWordHi(4)] & UINT64_C(0x0000800000000000))) \
|
||||
softfloat_raiseFlags(softfloat_flag_invalid)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
|
||||
@ -329,7 +394,17 @@ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* zPtr);
|
||||
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the
|
||||
| platform's normal endian order to form a 128-bit floating-point value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined INLINE && !defined softfloat_commonNaNToF128M
|
||||
INLINE
|
||||
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr) {
|
||||
zWPtr[indexWord(4, 3)] = defaultNaNF128UI96;
|
||||
zWPtr[indexWord(4, 2)] = defaultNaNF128UI64;
|
||||
zWPtr[indexWord(4, 1)] = defaultNaNF128UI32;
|
||||
zWPtr[indexWord(4, 0)] = defaultNaNF128UI0;
|
||||
}
|
||||
#else
|
||||
void softfloat_commonNaNToF128M(const struct commonNaN* aPtr, uint32_t* zWPtr);
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Assuming at least one of the two 128-bit floating-point values pointed to by
|
||||
|
51
softfloat/source/bf16_isSignalingNaN.c
Normal file
51
softfloat/source/bf16_isSignalingNaN.c
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
bool bf16_isSignalingNaN( bfloat16_t a )
|
||||
{
|
||||
union ui16_bf16 uA;
|
||||
|
||||
uA.f = a;
|
||||
return softfloat_isSigNaNBF16UI( uA.ui );
|
||||
|
||||
}
|
||||
|
90
softfloat/source/bf16_to_f32.c
Normal file
90
softfloat/source/bf16_to_f32.c
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
float32_t bf16_to_f32( bfloat16_t a )
|
||||
{
|
||||
union ui16_bf16 uA;
|
||||
uint_fast16_t uiA;
|
||||
bool sign;
|
||||
int_fast16_t exp;
|
||||
uint_fast16_t frac;
|
||||
struct commonNaN commonNaN;
|
||||
uint_fast32_t uiZ;
|
||||
struct exp8_sig16 normExpSig;
|
||||
union ui32_f32 uZ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
uA.f = a;
|
||||
uiA = uA.ui;
|
||||
sign = signBF16UI( uiA );
|
||||
exp = expBF16UI( uiA );
|
||||
frac = fracBF16UI( uiA );
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// NaN or Inf
|
||||
if ( exp == 0xFF ) {
|
||||
if ( frac ) {
|
||||
softfloat_bf16UIToCommonNaN( uiA, &commonNaN );
|
||||
uiZ = softfloat_commonNaNToF32UI( &commonNaN );
|
||||
} else {
|
||||
uiZ = packToF32UI( sign, 0xFF, 0 );
|
||||
}
|
||||
goto uiZ;
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// packToF32UI simply packs bitfields without any numerical change
|
||||
// which means it can be used directly for any BF16 to f32 conversions which
|
||||
// does not require bits manipulation
|
||||
// (that is everything where the 16-bit are just padded right with 16 zeros, including
|
||||
// subnormal numbers)
|
||||
uiZ = packToF32UI( sign, exp, ((uint_fast32_t) frac) <<16 );
|
||||
uiZ:
|
||||
uZ.ui = uiZ;
|
||||
return uZ.f;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
105
softfloat/source/f32_to_bf16.c
Normal file
105
softfloat/source/f32_to_bf16.c
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "specialize.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bfloat16_t f32_to_bf16( float32_t a )
|
||||
{
|
||||
union ui32_f32 uA;
|
||||
uint_fast32_t uiA;
|
||||
bool sign;
|
||||
int_fast16_t exp;
|
||||
uint_fast32_t frac;
|
||||
struct commonNaN commonNaN;
|
||||
uint_fast16_t uiZ, frac16;
|
||||
union ui16_bf16 uZ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
uA.f = a;
|
||||
uiA = uA.ui;
|
||||
sign = signF32UI( uiA );
|
||||
exp = expF32UI( uiA );
|
||||
frac = fracF32UI( uiA );
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// infinity or NaN cases
|
||||
if ( exp == 0xFF ) {
|
||||
if ( frac ) {
|
||||
// NaN case
|
||||
softfloat_f32UIToCommonNaN( uiA, &commonNaN );
|
||||
uiZ = softfloat_commonNaNToBF16UI( &commonNaN );
|
||||
} else {
|
||||
// infinity case
|
||||
uiZ = packToBF16UI( sign, 0xFF, 0 );
|
||||
}
|
||||
goto uiZ;
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// frac is a 24-bit mantissa, right shifted by 9
|
||||
// In the normal case, (24-9) = 15 are set
|
||||
frac16 = frac>>9 | ((frac & 0x1FF) != 0);
|
||||
if ( ! (exp | frac16) ) {
|
||||
uiZ = packToBF16UI( sign, 0, 0 );
|
||||
goto uiZ;
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// softfloat_roundPackToBF16 exponent argument (2nd argument)
|
||||
// must correspond to the exponent of fracIn[13] bits
|
||||
// (fracIn is the 3rd and last argument)
|
||||
uint_fast32_t mask = exp ? 0x4000 : 0x0; // implicit one mask added if input is a normal number
|
||||
// exponent for the lowest normal and largest subnormal should be equal
|
||||
// but is not in IEEE encoding so mantissa must be partially normalized
|
||||
// (by one bit) for subnormal numbers. Such that (exp - 1) corresponds
|
||||
// to the exponent of frac16[13]
|
||||
frac16 = frac16 << (exp ? 0 : 1);
|
||||
return softfloat_roundPackToBF16( sign, exp - 1, frac16 | mask );
|
||||
uiZ:
|
||||
uZ.ui = uiZ;
|
||||
return uZ.f;
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ float16_t f32_to_f16( float32_t a )
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
// frac is a 24-bit significand, the bottom 9 bits LSB are extracted and OR-red
|
||||
// into a sticky flag, the top 15 MSBs are extracted, the LSB of this top slice
|
||||
// is OR-red with the sticky
|
||||
frac16 = frac>>9 | ((frac & 0x1FF) != 0);
|
||||
if ( ! (exp | frac16) ) {
|
||||
uiZ = packToF16UI( sign, 0, 0 );
|
||||
|
@ -46,6 +46,10 @@ union ui16_f16 {
|
||||
uint16_t ui;
|
||||
float16_t f;
|
||||
};
|
||||
union ui16_bf16 {
|
||||
uint16_t ui;
|
||||
bfloat16_t f;
|
||||
};
|
||||
union ui32_f32 {
|
||||
uint32_t ui;
|
||||
float32_t f;
|
||||
@ -108,6 +112,18 @@ float16_t softfloat_addMagsF16(uint_fast16_t, uint_fast16_t);
|
||||
float16_t softfloat_subMagsF16(uint_fast16_t, uint_fast16_t);
|
||||
float16_t softfloat_mulAddF16(uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define signBF16UI(a) ((bool)((uint16_t)(a) >> 15))
|
||||
#define expBF16UI(a) ((int_fast16_t)((a) >> 7) & 0xFF)
|
||||
#define fracBF16UI(a) ((a)&0x07F)
|
||||
#define packToBF16UI(sign, exp, sig) (((uint16_t)(sign) << 15) + ((uint16_t)(exp) << 7) + (sig))
|
||||
|
||||
#define isNaNBF16UI(a) (((~(a)&0x7FC0) == 0) && ((a)&0x07F))
|
||||
|
||||
bfloat16_t softfloat_roundPackToBF16(bool, int_fast16_t, uint_fast16_t);
|
||||
struct exp8_sig16 softfloat_normSubnormalBF16Sig(uint_fast16_t);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define signF32UI(a) ((bool)((uint32_t)(a) >> 31))
|
||||
|
@ -76,13 +76,13 @@ enum {
|
||||
| Software floating-point exception flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags;
|
||||
enum {
|
||||
typedef enum {
|
||||
softfloat_flag_inexact = 1,
|
||||
softfloat_flag_underflow = 2,
|
||||
softfloat_flag_overflow = 4,
|
||||
softfloat_flag_infinite = 8,
|
||||
softfloat_flag_invalid = 16
|
||||
};
|
||||
} exceptionFlag_t;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Routine to raise any or all of the software floating-point exception flags.
|
||||
@ -164,6 +164,13 @@ bool f16_le_quiet(float16_t, float16_t);
|
||||
bool f16_lt_quiet(float16_t, float16_t);
|
||||
bool f16_isSignalingNaN(float16_t);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| 16-bit (brain float 16) floating-point operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32_t bf16_to_f32(bfloat16_t);
|
||||
bfloat16_t f32_to_bf16(float32_t);
|
||||
bool bf16_isSignalingNaN(bfloat16_t);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| 32-bit (single-precision) floating-point operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
@ -50,6 +50,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
typedef struct {
|
||||
uint16_t v;
|
||||
} float16_t;
|
||||
typedef struct {
|
||||
uint16_t v;
|
||||
} bfloat16_t;
|
||||
typedef struct {
|
||||
uint32_t v;
|
||||
} float32_t;
|
||||
|
@ -221,4 +221,3 @@ float32_t
|
||||
return uZ.f;
|
||||
|
||||
}
|
||||
|
||||
|
52
softfloat/source/s_normSubnormalBF16Sig.c
Normal file
52
softfloat/source/s_normSubnormalBF16Sig.c
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
|
||||
struct exp8_sig16 softfloat_normSubnormalBF16Sig( uint_fast16_t sig )
|
||||
{
|
||||
int_fast8_t shiftDist;
|
||||
struct exp8_sig16 z;
|
||||
|
||||
shiftDist = softfloat_countLeadingZeros16( sig ) - 8;
|
||||
z.exp = 1 - shiftDist;
|
||||
z.sig = sig<<shiftDist;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
114
softfloat/source/s_roundPackToBF16.c
Normal file
114
softfloat/source/s_roundPackToBF16.c
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
|
||||
Package, Release 3e, by John R. Hauser.
|
||||
|
||||
Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of
|
||||
California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
#include "internals.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
/** sig last significant bit is sig[7], the 7 LSBs will be used for rounding */
|
||||
bfloat16_t
|
||||
softfloat_roundPackToBF16( bool sign, int_fast16_t exp, uint_fast16_t sig )
|
||||
{
|
||||
uint_fast8_t roundingMode;
|
||||
bool roundNearEven;
|
||||
uint_fast8_t roundIncrement, roundBits;
|
||||
bool isTiny;
|
||||
uint_fast16_t uiZ;
|
||||
union ui16_bf16 uZ;
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
roundingMode = softfloat_roundingMode;
|
||||
roundNearEven = (roundingMode == softfloat_round_near_even);
|
||||
roundIncrement = 0x40;
|
||||
if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) {
|
||||
roundIncrement =
|
||||
(roundingMode
|
||||
== (sign ? softfloat_round_min : softfloat_round_max))
|
||||
? 0x7F
|
||||
: 0;
|
||||
}
|
||||
roundBits = sig & 0x7F;
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
if ( 0xFD <= (unsigned int) exp ) {
|
||||
if ( exp < 0 ) {
|
||||
/*----------------------------------------------------------------
|
||||
*----------------------------------------------------------------*/
|
||||
isTiny =
|
||||
(softfloat_detectTininess == softfloat_tininess_beforeRounding)
|
||||
|| (exp < -1) || (sig + roundIncrement < 0x8000);
|
||||
sig = softfloat_shiftRightJam32( sig, -exp );
|
||||
exp = 0;
|
||||
roundBits = sig & 0x7F;
|
||||
if ( isTiny && roundBits ) {
|
||||
softfloat_raiseFlags( softfloat_flag_underflow );
|
||||
}
|
||||
} else if ( (0xFD < exp) || (0x8000 <= sig + roundIncrement) ) {
|
||||
/*----------------------------------------------------------------
|
||||
*----------------------------------------------------------------*/
|
||||
softfloat_raiseFlags(
|
||||
softfloat_flag_overflow | softfloat_flag_inexact );
|
||||
uiZ = packToBF16UI( sign, 0xFF, 0 ) - ! roundIncrement;
|
||||
goto uiZ;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
sig = (sig + roundIncrement)>>7;
|
||||
if ( roundBits ) {
|
||||
softfloat_exceptionFlags |= softfloat_flag_inexact;
|
||||
#ifdef SOFTFLOAT_ROUND_ODD
|
||||
if ( roundingMode == softfloat_round_odd ) {
|
||||
sig |= 1;
|
||||
goto packReturn;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sig &= ~(uint_fast16_t) (! (roundBits ^ 0x40) & roundNearEven);
|
||||
if ( ! sig ) exp = 0;
|
||||
/*------------------------------------------------------------------------
|
||||
*------------------------------------------------------------------------*/
|
||||
packReturn:
|
||||
uiZ = packToBF16UI( sign, exp, sig );
|
||||
uiZ:
|
||||
uZ.ui = uiZ;
|
||||
return uZ.f;
|
||||
|
||||
}
|
||||
|
35
src/elfio.cpp
Normal file
35
src/elfio.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#ifdef _MSC_VER
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
#define ELFIO_NO_INTTYPES
|
||||
#endif
|
||||
|
||||
#include <elfio/elfio_dump.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if(argc != 2) {
|
||||
printf("Usage: elfdump <file_name>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
elfio reader;
|
||||
|
||||
if(!reader.load(argv[1])) {
|
||||
printf("File %s is not found or it is not an ELF file\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dump::header(std::cout, reader);
|
||||
dump::section_headers(std::cout, reader);
|
||||
dump::segment_headers(std::cout, reader);
|
||||
dump::symbol_tables(std::cout, reader);
|
||||
dump::notes(std::cout, reader);
|
||||
dump::modinfo(std::cout, reader);
|
||||
dump::dynamic_tags(std::cout, reader);
|
||||
dump::section_datas(std::cout, reader);
|
||||
dump::segment_datas(std::cout, reader);
|
||||
|
||||
return 0;
|
||||
}
|
@ -51,8 +51,8 @@ public:
|
||||
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;
|
||||
iss::status read_custom_csr(unsigned addr, reg_t& val) override;
|
||||
iss::status write_custom_csr(unsigned addr, reg_t val) override;
|
||||
};
|
||||
|
||||
template <typename BASE>
|
||||
@ -68,7 +68,7 @@ inline hwl<BASE>::hwl(feature_config cfg)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t& val) {
|
||||
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_csr(unsigned addr, reg_t& val) {
|
||||
switch(addr) {
|
||||
case 0x800:
|
||||
val = this->reg.lpstart0;
|
||||
@ -92,7 +92,7 @@ template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_cs
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::write_custom_csr(unsigned addr, reg_t val) {
|
||||
switch(addr) {
|
||||
case 0x800:
|
||||
this->reg.lpstart0 = val;
|
||||
|
@ -35,14 +35,30 @@
|
||||
#ifndef _RISCV_HART_COMMON
|
||||
#define _RISCV_HART_COMMON
|
||||
|
||||
#include "iss/arch_if.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <elfio/elfio.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/log_categories.h>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <util/logging.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) ::__builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) ::__builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
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, FEAT_TCM = 16 };
|
||||
|
||||
enum riscv_csr {
|
||||
@ -296,6 +312,104 @@ inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t* const
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct riscv_hart_common {
|
||||
riscv_hart_common(){};
|
||||
~riscv_hart_common() {
|
||||
if(io_buf.str().length()) {
|
||||
CPPLOG(INFO) << "tohost send '" << io_buf.str() << "'";
|
||||
}
|
||||
};
|
||||
std::unordered_map<std::string, uint64_t> symbol_table;
|
||||
uint64_t entry_address{0};
|
||||
uint64_t tohost = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t fromhost = std::numeric_limits<uint64_t>::max();
|
||||
std::stringstream io_buf;
|
||||
|
||||
bool read_elf_file(std::string name, uint8_t expected_elf_class,
|
||||
std::function<iss::status(uint64_t, uint64_t, const uint8_t* const)> cb) {
|
||||
// Create elfio reader
|
||||
ELFIO::elfio reader;
|
||||
// Load ELF data
|
||||
if(reader.load(name)) {
|
||||
// check elf properties
|
||||
if(reader.get_class() != expected_elf_class)
|
||||
return false;
|
||||
if(reader.get_type() != ELFIO::ET_EXEC)
|
||||
return false;
|
||||
if(reader.get_machine() != ELFIO::EM_RISCV)
|
||||
return false;
|
||||
entry_address = reader.get_entry();
|
||||
for(const auto& pseg : reader.segments) {
|
||||
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
|
||||
const auto seg_data = pseg->get_data();
|
||||
const auto type = pseg->get_type();
|
||||
if(type == 1 && fsize > 0) {
|
||||
auto res = cb(pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
|
||||
if(res != iss::Ok)
|
||||
CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
|
||||
}
|
||||
}
|
||||
const auto sym_sec = reader.sections[".symtab"];
|
||||
if(ELFIO::SHT_SYMTAB == sym_sec->get_type() || ELFIO::SHT_DYNSYM == sym_sec->get_type()) {
|
||||
ELFIO::symbol_section_accessor symbols(reader, sym_sec);
|
||||
auto sym_no = symbols.get_symbols_num();
|
||||
std::string name;
|
||||
ELFIO::Elf64_Addr value = 0;
|
||||
ELFIO::Elf_Xword size = 0;
|
||||
unsigned char bind = 0;
|
||||
unsigned char type = 0;
|
||||
ELFIO::Elf_Half section = 0;
|
||||
unsigned char other = 0;
|
||||
for(auto i = 0U; i < sym_no; ++i) {
|
||||
symbols.get_symbol(i, name, value, size, bind, type, section, other);
|
||||
if(name != "") {
|
||||
this->symbol_table[name] = value;
|
||||
#ifndef NDEBUG
|
||||
CPPLOG(DEBUG) << "Found Symbol " << name;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
try {
|
||||
tohost = symbol_table.at("tohost");
|
||||
} catch(std::out_of_range& e) {
|
||||
}
|
||||
try {
|
||||
fromhost = symbol_table.at("fromhost");
|
||||
} catch(std::out_of_range& e) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
iss::status execute_sys_write(arch_if* aif, const std::array<uint64_t, 8>& loaded_payload, unsigned mem_type) {
|
||||
uint64_t fd = loaded_payload[1];
|
||||
uint64_t buf_ptr = loaded_payload[2];
|
||||
uint64_t len = loaded_payload[3];
|
||||
std::vector<char> buf(len);
|
||||
if(aif->read(address_type::PHYSICAL, access_type::DEBUG_READ, mem_type, buf_ptr, len, reinterpret_cast<uint8_t*>(buf.data()))) {
|
||||
CPPLOG(ERR) << "SYS_WRITE buffer read went wrong";
|
||||
return iss::Err;
|
||||
}
|
||||
// we disregard the fd and just log to stdout
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
if(buf[i] == '\n' || buf[i] == '\0') {
|
||||
CPPLOG(INFO) << "tohost send '" << io_buf.str() << "'";
|
||||
io_buf.str("");
|
||||
} else
|
||||
io_buf << buf[i];
|
||||
}
|
||||
|
||||
// Not sure what the correct return value should be
|
||||
uint8_t ret_val = 1;
|
||||
if(fromhost != std::numeric_limits<uint64_t>::max())
|
||||
if(aif->write(address_type::PHYSICAL, access_type::DEBUG_WRITE, mem_type, fromhost, 1, &ret_val)) {
|
||||
CPPLOG(ERR) << "Fromhost write went wrong";
|
||||
return iss::Err;
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace arch
|
||||
} // namespace iss
|
||||
|
@ -39,7 +39,14 @@
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "iss/log_categories.h"
|
||||
#include "iss/vm_if.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include "riscv_hart_common.h"
|
||||
#include "util/logging.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <elfio/elf_types.hpp>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -55,18 +62,13 @@
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
#include <iss/semihosting/semihosting.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_m_p : public BASE {
|
||||
template <typename BASE, features_e FEAT = FEAT_NONE, typename LOGCAT = logging::disass>
|
||||
class riscv_hart_m_p : public BASE, public riscv_hart_common {
|
||||
protected:
|
||||
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
const std::array<const char*, 16> trap_str = {{""
|
||||
@ -93,7 +95,7 @@ protected:
|
||||
|
||||
public:
|
||||
using core = BASE;
|
||||
using this_class = riscv_hart_m_p<BASE, FEAT>;
|
||||
using this_class = riscv_hart_m_p<BASE, FEAT, LOGCAT>;
|
||||
using phys_addr_t = typename core::phys_addr_t;
|
||||
using reg_t = typename core::reg_t;
|
||||
using addr_t = typename core::addr_t;
|
||||
@ -280,8 +282,8 @@ public:
|
||||
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", pc, instr, (reg_t)state.mstatus,
|
||||
this->reg.icount + cycle_offset);
|
||||
NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", pc, instr, (reg_t)state.mstatus,
|
||||
this->reg.cycle + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
|
||||
@ -290,10 +292,12 @@ public:
|
||||
|
||||
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
|
||||
|
||||
void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; };
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT>& arch)
|
||||
riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch)
|
||||
: arch(arch) {}
|
||||
/**
|
||||
* get the name of this architecture
|
||||
@ -312,7 +316,7 @@ protected:
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
@ -322,7 +326,9 @@ protected:
|
||||
|
||||
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
|
||||
|
||||
riscv_hart_m_p<BASE, FEAT>& arch;
|
||||
std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
|
||||
|
||||
riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch;
|
||||
};
|
||||
|
||||
friend struct riscv_instrumentation_if;
|
||||
@ -342,17 +348,15 @@ protected:
|
||||
int64_t instret_offset{0};
|
||||
uint64_t minstret_csr{0};
|
||||
reg_t fault_data;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
uint64_t fromhost = fromhost_dflt;
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
riscv_instrumentation_if instr_if;
|
||||
|
||||
semihosting_cb_t<reg_t> semihosting_cb;
|
||||
|
||||
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
|
||||
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
|
||||
using csr_page_type = typename csr_type::page_type;
|
||||
mem_type mem;
|
||||
csr_type csr;
|
||||
std::stringstream uart_buf;
|
||||
std::unordered_map<reg_t, uint64_t> ptw;
|
||||
std::unordered_map<uint64_t, uint8_t> atomic_reservation;
|
||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||
@ -374,8 +378,8 @@ protected:
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
iss::status read_csr_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_csr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_plain(unsigned addr, reg_t& val);
|
||||
iss::status write_plain(unsigned addr, reg_t val);
|
||||
iss::status read_null(unsigned addr, reg_t& val);
|
||||
iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; }
|
||||
iss::status read_cycle(unsigned addr, reg_t& val);
|
||||
@ -396,17 +400,19 @@ protected:
|
||||
iss::status read_intstatus(unsigned addr, reg_t& val);
|
||||
iss::status write_intthresh(unsigned addr, reg_t val);
|
||||
iss::status write_xtvt(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_dcsr_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_dpc_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_debug(unsigned addr, reg_t& val);
|
||||
iss::status write_dscratch(unsigned addr, reg_t val);
|
||||
iss::status read_dpc(unsigned addr, reg_t& val);
|
||||
iss::status write_dpc(unsigned addr, reg_t val);
|
||||
iss::status read_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; };
|
||||
virtual iss::status read_custom_csr(unsigned addr, reg_t& val) { return iss::status::Err; };
|
||||
virtual iss::status write_custom_csr(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; }
|
||||
void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr; }
|
||||
void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr; }
|
||||
|
||||
reg_t mhartid_reg{0x0};
|
||||
|
||||
@ -419,6 +425,7 @@ protected:
|
||||
feature_config cfg;
|
||||
unsigned mcause_max_irq{(FEAT & features_e::FEAT_CLIC) ? std::max(16U, static_cast<unsigned>(traits<BASE>::CLIC_NUM_IRQ)) : 16U};
|
||||
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};
|
||||
@ -430,8 +437,8 @@ protected:
|
||||
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
|
||||
: state()
|
||||
, instr_if(*this)
|
||||
, cfg(cfg) {
|
||||
@ -441,19 +448,22 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
|
||||
uart_buf.str("");
|
||||
if(traits<BASE>::FLEN > 0) {
|
||||
csr_rd_cb[fcsr] = &this_class::read_fcsr;
|
||||
csr_wr_cb[fcsr] = &this_class::write_fcsr;
|
||||
}
|
||||
for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
if(traits<BASE>::XLEN == 32)
|
||||
for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
@ -461,18 +471,17 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
if(traits<BASE>::XLEN == 32)
|
||||
for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
// csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// common regs
|
||||
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
|
||||
for(auto addr : roaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[addr] = &this_class::read_plain;
|
||||
csr_wr_cb[addr] = &this_class::write_null;
|
||||
}
|
||||
const std::array<unsigned, 4> rwaddrs{{mepc, mtvec, mscratch, mtval}};
|
||||
for(auto addr : rwaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[addr] = &this_class::read_plain;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
// special handling & overrides
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
@ -513,7 +522,7 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
csr_wr_cb[marchid] = &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_rd_cb[mtvt] = &this_class::read_plain;
|
||||
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;
|
||||
@ -523,7 +532,7 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
// 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_rd_cb[mintthresh] = &this_class::read_plain;
|
||||
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;
|
||||
@ -549,88 +558,33 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
|
||||
}
|
||||
if(FEAT & FEAT_DEBUG) {
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
|
||||
csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dpc] = &this_class::write_dpc_reg;
|
||||
csr_rd_cb[dpc] = &this_class::read_dpc_reg;
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dscratch;
|
||||
csr_rd_cb[dscratch0] = &this_class::read_debug;
|
||||
csr_wr_cb[dscratch1] = &this_class::write_dscratch;
|
||||
csr_rd_cb[dscratch1] = &this_class::read_debug;
|
||||
csr_wr_cb[dpc] = &this_class::write_dpc;
|
||||
csr_rd_cb[dpc] = &this_class::read_dpc;
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_debug;
|
||||
}
|
||||
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) {
|
||||
FILE* fp = fopen(name.c_str(), "r");
|
||||
if(fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(fp);
|
||||
if(n != 4)
|
||||
throw std::runtime_error("input file has insufficient size");
|
||||
buf[4] = 0;
|
||||
if(strcmp(buf.data() + 1, "ELF") == 0) {
|
||||
// Create elfio reader
|
||||
ELFIO::elfio reader;
|
||||
// Load ELF data
|
||||
if(!reader.load(name))
|
||||
throw std::runtime_error("could not process elf file");
|
||||
// check elf properties
|
||||
if(reader.get_class() != ELFCLASS32)
|
||||
if(sizeof(reg_t) == 4)
|
||||
throw std::runtime_error("wrong elf class in file");
|
||||
if(reader.get_type() != ET_EXEC)
|
||||
throw std::runtime_error("wrong elf type in file");
|
||||
if(reader.get_machine() != EM_RISCV)
|
||||
throw std::runtime_error("wrong elf machine in file");
|
||||
auto entry = reader.get_entry();
|
||||
for(const auto pseg : reader.segments) {
|
||||
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
|
||||
const auto seg_data = pseg->get_data();
|
||||
if(fsize > 0) {
|
||||
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
|
||||
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
|
||||
if(res != iss::Ok)
|
||||
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) {
|
||||
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64,
|
||||
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
|
||||
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size,
|
||||
data);
|
||||
})) {
|
||||
return std::make_pair(entry_address, true);
|
||||
}
|
||||
}
|
||||
for(const auto sec : reader.sections) {
|
||||
if(sec->get_name() == ".symtab") {
|
||||
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
|
||||
ELFIO::symbol_section_accessor symbols(reader, sec);
|
||||
auto sym_no = symbols.get_symbols_num();
|
||||
std::string name;
|
||||
ELFIO::Elf64_Addr value = 0;
|
||||
ELFIO::Elf_Xword size = 0;
|
||||
unsigned char bind = 0;
|
||||
unsigned char type = 0;
|
||||
ELFIO::Elf_Half section = 0;
|
||||
unsigned char other = 0;
|
||||
for(auto i = 0U; i < sym_no; ++i) {
|
||||
symbols.get_symbol(i, name, value, size, bind, type, section, other);
|
||||
if(name == "tohost") {
|
||||
tohost = value;
|
||||
} else if(name == "fromhost") {
|
||||
fromhost = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sec->get_name() == ".tohost") {
|
||||
tohost = sec->get_address();
|
||||
fromhost = tohost + 0x40;
|
||||
}
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
return std::make_pair(entry_address, false);
|
||||
}
|
||||
|
||||
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,
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
inline void riscv_hart_m_p<BASE, FEAT, LOGCAT>::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(
|
||||
@ -642,22 +596,22 @@ inline void riscv_hart_m_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t
|
||||
memfn_write.insert(std::begin(memfn_write) + idx, wr_fn);
|
||||
}
|
||||
|
||||
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, const uint64_t addr,
|
||||
const unsigned length, uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read(const address_type type, const access_type access, const uint32_t space,
|
||||
const uint64_t addr, const unsigned length, uint8_t* const data) {
|
||||
#ifndef NDEBUG
|
||||
if(access && iss::access_type::DEBUG) {
|
||||
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else if(access && iss::access_type::FETCH) {
|
||||
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else {
|
||||
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
switch(space) {
|
||||
case traits<BASE>::MEM: {
|
||||
auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : length;
|
||||
auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min<unsigned>(length, sizeof(reg_t));
|
||||
if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) {
|
||||
fault_data = addr;
|
||||
if(is_debug(access))
|
||||
@ -673,7 +627,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
}
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()) {
|
||||
if(!is_fetch(access) && memfn_range.size()) {
|
||||
auto it =
|
||||
std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a) {
|
||||
return std::get<0>(a) <= phys_addr.val && (std::get<0>(a) + std::get<1>(a)) > phys_addr.val;
|
||||
@ -692,8 +646,10 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
}
|
||||
return res;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
} break;
|
||||
@ -720,36 +676,38 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, const access_type access, const uint32_t space,
|
||||
const uint64_t addr, const unsigned length, const uint8_t* const data) {
|
||||
#ifndef NDEBUG
|
||||
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
|
||||
switch(length) {
|
||||
case 8:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 4:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 2:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 1:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
default:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
@ -763,14 +721,15 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length > 1 && (addr & (length - 1)) && (access & access_type::DEBUG) != access_type::DEBUG) {
|
||||
auto alignment = std::min<unsigned>(length, sizeof(reg_t));
|
||||
if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) {
|
||||
this->reg.trap_state = (1UL << 31) | 6 << 16;
|
||||
fault_data = addr;
|
||||
return iss::Err;
|
||||
}
|
||||
phys_addr_t phys_addr{access, space, addr};
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()) {
|
||||
if(!is_fetch(access) && memfn_range.size()) {
|
||||
auto it =
|
||||
std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a) {
|
||||
return std::get<0>(a) <= phys_addr.val && (std::get<0>(a) + std::get<1>(a)) > phys_addr.val;
|
||||
@ -783,8 +742,8 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
} else {
|
||||
res = write_mem(phys_addr, length, data);
|
||||
}
|
||||
if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) {
|
||||
this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
if(unlikely(res != iss::Ok && !is_debug(access))) {
|
||||
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data = addr;
|
||||
}
|
||||
return res;
|
||||
@ -793,40 +752,6 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
fault_data = ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
|
||||
if((addr + length) > mem.size())
|
||||
return iss::Err;
|
||||
switch(addr) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
return iss::Ok;
|
||||
case 0x10008000: { // HFROSC base, hfrosccfg reg
|
||||
auto& p = mem(addr / mem.page_size);
|
||||
auto offs = addr & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
if(x & 0x40)
|
||||
x |= 0x80; // hfroscrdy = 1 if hfroscen==1
|
||||
return iss::Ok;
|
||||
}
|
||||
case 0x10008008: { // HFROSC base, pllcfg reg
|
||||
auto& p = mem(addr / mem.page_size);
|
||||
auto offs = addr & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
x |= 0x80; // set pll lock upon writing
|
||||
return iss::Ok;
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::CSR: {
|
||||
if(length != sizeof(reg_t))
|
||||
@ -853,13 +778,16 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t& val) {
|
||||
if(addr >= csr.size())
|
||||
return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
@ -871,7 +799,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t val) {
|
||||
if(addr >= csr.size())
|
||||
return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
@ -885,23 +814,27 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t& val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_null(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_null(unsigned addr, reg_t& val) {
|
||||
val = 0;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_plain(unsigned addr, reg_t& val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_plain(unsigned addr, reg_t val) {
|
||||
csr[addr] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
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;
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_cycle(unsigned addr, reg_t& val) {
|
||||
auto cycle_val = this->reg.cycle + cycle_offset;
|
||||
if(addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if(addr == mcycleh) {
|
||||
@ -910,7 +843,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_t val) {
|
||||
if(sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
mcycle_csr = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
@ -920,11 +854,12 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr - this->reg.icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg_t& val) {
|
||||
if((addr & 0xff) == (minstret & 0xff)) {
|
||||
val = static_cast<reg_t>(this->reg.instret);
|
||||
} else if((addr & 0xff) == (minstreth & 0xff)) {
|
||||
@ -933,7 +868,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, reg_t val) {
|
||||
if(sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
@ -947,8 +883,9 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t& val) {
|
||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_time(unsigned addr, reg_t& val) {
|
||||
uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if(addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if(addr == timeh) {
|
||||
@ -959,23 +896,27 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_tvec(unsigned addr, reg_t& val) {
|
||||
val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_status(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_status(unsigned addr, reg_t& val) {
|
||||
val = state.mstatus & hart_state_type::get_mask();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_status(unsigned addr, reg_t val) {
|
||||
state.write_mstatus(val);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_cause(unsigned addr, reg_t& val) {
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) {
|
||||
val = csr[addr] & ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
|
||||
val |= clic_mprev_lvl << 16;
|
||||
@ -986,7 +927,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_cause(unsigned addr, reg_t val) {
|
||||
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);
|
||||
@ -1000,36 +942,42 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_hartid(unsigned addr, reg_t& val) {
|
||||
val = mhartid_reg;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ie(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_ie(unsigned addr, reg_t& val) {
|
||||
auto mask = get_irq_mask();
|
||||
val = csr[mie] & mask;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_ie(unsigned addr, reg_t val) {
|
||||
auto mask = get_irq_mask();
|
||||
csr[mie] = (csr[mie] & ~mask) | (val & mask);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ip(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_ip(unsigned addr, reg_t& val) {
|
||||
auto mask = get_irq_mask();
|
||||
val = csr[mip] & mask;
|
||||
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, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_epc(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & get_pc_mask();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_dcsr(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
// +-------------- ebreakm
|
||||
@ -1040,51 +988,70 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_debug(unsigned addr, reg_t& val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dscratch(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
csr[addr] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_dpc(unsigned addr, reg_t& val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
val = this->reg.DPC;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dpc(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
this->reg.DPC = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_fcsr(unsigned addr, reg_t& val) {
|
||||
val = this->get_fcsr();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_fcsr(unsigned addr, reg_t val) {
|
||||
this->set_fcsr(val);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & ~0x3fULL;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
|
||||
switch(paddr.val) {
|
||||
default: {
|
||||
for(auto offs = 0U; offs < length; ++offs) {
|
||||
@ -1095,68 +1062,59 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
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) {
|
||||
switch(paddr.val) {
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
break;
|
||||
default: {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
|
||||
mem_type::page_type& p = mem(paddr.val / mem.page_size);
|
||||
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
||||
// tohost handling in case of riscv-test
|
||||
// according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754:
|
||||
if(paddr.access && iss::access_type::FUNC) {
|
||||
auto tohost_upper =
|
||||
(traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
if(tohost_lower || tohost_upper) {
|
||||
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
|
||||
if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
|
||||
switch(hostvar >> 48) {
|
||||
case 0:
|
||||
if(hostvar != 0x1) {
|
||||
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
if(paddr.val == tohost) {
|
||||
reg_t cur_data = *reinterpret_cast<const reg_t*>(data);
|
||||
// Extract Device (bits 63:56)
|
||||
uint8_t device = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 56) & 0xFF;
|
||||
// Extract Command (bits 55:48)
|
||||
uint8_t command = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 48) & 0xFF;
|
||||
// Extract payload (bits 47:0)
|
||||
uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL;
|
||||
if(payload_addr & 1) {
|
||||
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr
|
||||
<< "), stopping simulation";
|
||||
} else {
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = hostvar;
|
||||
#ifndef WITH_TCC
|
||||
throw(iss::simulation_stopped(hostvar));
|
||||
#endif
|
||||
break;
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if(c == '\n' || c == 0) {
|
||||
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else
|
||||
uart_buf << c;
|
||||
to_host_wr_cnt = 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
} else if(device == 0 && command == 0) {
|
||||
std::array<uint64_t, 8> loaded_payload;
|
||||
if(read(address_type::PHYSICAL, access_type::DEBUG_READ, traits<BASE>::MEM, payload_addr, 8 * sizeof(uint64_t),
|
||||
reinterpret_cast<uint8_t*>(loaded_payload.data())) == iss::Err)
|
||||
CPPLOG(ERR) << "Syscall read went wrong";
|
||||
uint64_t syscall_num = loaded_payload.at(0);
|
||||
if(syscall_num == 64) { // SYS_WRITE
|
||||
return execute_sys_write(this, loaded_payload, traits<BASE>::MEM);
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num
|
||||
<< ") not implemented";
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
} else if(tohost_lower)
|
||||
to_host_wr_cnt++;
|
||||
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost functionality not implemented for device " << device << " and command " << command;
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
}
|
||||
if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
uint64_t fhostvar = *reinterpret_cast<uint64_t*>(p.data() + (fromhost & mem.page_addr_mask));
|
||||
*reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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)
|
||||
@ -1175,8 +1133,8 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length
|
||||
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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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
|
||||
@ -1191,12 +1149,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned lengt
|
||||
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, typename LOGCAT> inline void riscv_hart_m_p<BASE, FEAT, LOGCAT>::reset(uint64_t address) {
|
||||
BASE::reset(address);
|
||||
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, typename LOGCAT> void riscv_hart_m_p<BASE, FEAT, LOGCAT>::check_interrupt() {
|
||||
// TODO: Implement CLIC functionality
|
||||
// auto ideleg = csr[mideleg];
|
||||
// Multiple simultaneous interrupts and traps at the same privilege level are
|
||||
@ -1219,7 +1177,8 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
||||
}
|
||||
}
|
||||
|
||||
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, typename LOGCAT>
|
||||
uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) {
|
||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||
// calculate and write mcause val
|
||||
auto const trap_id = bit_sub<0, 16>(flags);
|
||||
@ -1240,10 +1199,10 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
*/
|
||||
switch(cause) {
|
||||
case 0:
|
||||
csr[mtval] = static_cast<reg_t>(addr);
|
||||
csr[mtval] = static_cast<reg_t>(tval);
|
||||
break;
|
||||
case 2:
|
||||
csr[mtval] = (!has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff;
|
||||
csr[mtval] = (!has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff;
|
||||
break;
|
||||
case 3:
|
||||
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||
@ -1253,6 +1212,31 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
} else {
|
||||
csr[mtval] = addr;
|
||||
}
|
||||
if(semihosting_cb) {
|
||||
// Check for semihosting call
|
||||
phys_addr_t p_addr(access_type::DEBUG_READ, traits<BASE>::MEM, addr - 4);
|
||||
std::array<uint8_t, 8> data;
|
||||
// check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07
|
||||
this->read_mem(p_addr, 4, data.data());
|
||||
p_addr.val += 8;
|
||||
this->read_mem(p_addr, 4, data.data() + 4);
|
||||
|
||||
const std::array<uint8_t, 8> ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40};
|
||||
if(data == ref_data) {
|
||||
this->reg.NEXT_PC = addr + 8;
|
||||
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
#else
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
#endif
|
||||
NSCLOG(INFO, LOGCAT) << "Semihosting call at address " << buffer.data() << " occurred ";
|
||||
|
||||
semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/);
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@ -1303,18 +1287,18 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
#endif
|
||||
if((flags & 0xffffffff) != 0xffffffff)
|
||||
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' ("
|
||||
NSCLOG(INFO, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' ("
|
||||
<< cause << ")"
|
||||
<< " at address " << buffer.data() << " occurred";
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::leave_trap(uint64_t flags) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT> uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::leave_trap(uint64_t flags) {
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
state.mstatus.MPIE = 1;
|
||||
// sets the pc to the value stored in the x epc register.
|
||||
this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
|
||||
CLOG(INFO, disass) << "Executing xRET";
|
||||
NSCLOG(INFO, LOGCAT) << "Executing xRET";
|
||||
check_interrupt();
|
||||
this->reg.trap_state = this->reg.pending_trap;
|
||||
return this->reg.NEXT_PC;
|
||||
|
@ -39,7 +39,14 @@
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "iss/log_categories.h"
|
||||
#include "iss/vm_if.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include "riscv_hart_common.h"
|
||||
#include "util/logging.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <elfio/elf_types.hpp>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -55,18 +62,12 @@
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
#include <iss/semihosting/semihosting.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
template <typename BASE> class riscv_hart_msu_vp : public BASE {
|
||||
template <typename BASE> class riscv_hart_msu_vp : public BASE, public riscv_hart_common {
|
||||
protected:
|
||||
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
const std::array<const char*, 16> trap_str = {{""
|
||||
@ -332,7 +333,7 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus,
|
||||
this->reg.icount + cycle_offset);
|
||||
this->reg.cycle + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
|
||||
@ -341,6 +342,8 @@ public:
|
||||
|
||||
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
|
||||
|
||||
void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; };
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
@ -363,7 +366,7 @@ protected:
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
@ -373,6 +376,8 @@ protected:
|
||||
|
||||
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
|
||||
|
||||
std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
|
||||
|
||||
riscv_hart_msu_vp<BASE>& arch;
|
||||
};
|
||||
|
||||
@ -393,18 +398,16 @@ protected:
|
||||
uint64_t minstret_csr{0};
|
||||
reg_t fault_data;
|
||||
std::array<vm_info, 2> vm;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
uint64_t fromhost = fromhost_dflt;
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
riscv_instrumentation_if instr_if;
|
||||
|
||||
std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb;
|
||||
|
||||
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
|
||||
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
|
||||
using csr_page_type = typename csr_type::page_type;
|
||||
mem_type mem;
|
||||
csr_type csr;
|
||||
void update_vm_info();
|
||||
std::stringstream uart_buf;
|
||||
std::unordered_map<reg_t, uint64_t> ptw;
|
||||
std::unordered_map<uint64_t, uint8_t> atomic_reservation;
|
||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||
@ -459,7 +462,6 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
|
||||
uart_buf.str("");
|
||||
for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
@ -555,70 +557,14 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
|
||||
}
|
||||
|
||||
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) {
|
||||
FILE* fp = fopen(name.c_str(), "r");
|
||||
if(fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(fp);
|
||||
if(n != 4)
|
||||
throw std::runtime_error("input file has insufficient size");
|
||||
buf[4] = 0;
|
||||
if(strcmp(buf.data() + 1, "ELF") == 0) {
|
||||
// Create elfio reader
|
||||
ELFIO::elfio reader;
|
||||
// Load ELF data
|
||||
if(!reader.load(name))
|
||||
throw std::runtime_error("could not process elf file");
|
||||
// check elf properties
|
||||
if(reader.get_class() != ELFCLASS32)
|
||||
if(sizeof(reg_t) == 4)
|
||||
throw std::runtime_error("wrong elf class in file");
|
||||
if(reader.get_type() != ET_EXEC)
|
||||
throw std::runtime_error("wrong elf type in file");
|
||||
if(reader.get_machine() != EM_RISCV)
|
||||
throw std::runtime_error("wrong elf machine in file");
|
||||
auto entry = reader.get_entry();
|
||||
for(const auto pseg : reader.segments) {
|
||||
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
|
||||
const auto seg_data = pseg->get_data();
|
||||
if(fsize > 0) {
|
||||
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
|
||||
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
|
||||
if(res != iss::Ok)
|
||||
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
|
||||
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64,
|
||||
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
|
||||
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size,
|
||||
data);
|
||||
})) {
|
||||
return std::make_pair(entry_address, true);
|
||||
}
|
||||
}
|
||||
for(const auto sec : reader.sections) {
|
||||
if(sec->get_name() == ".symtab") {
|
||||
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
|
||||
ELFIO::symbol_section_accessor symbols(reader, sec);
|
||||
auto sym_no = symbols.get_symbols_num();
|
||||
std::string name;
|
||||
ELFIO::Elf64_Addr value = 0;
|
||||
ELFIO::Elf_Xword size = 0;
|
||||
unsigned char bind = 0;
|
||||
unsigned char type = 0;
|
||||
ELFIO::Elf_Half section = 0;
|
||||
unsigned char other = 0;
|
||||
for(auto i = 0U; i < sym_no; ++i) {
|
||||
symbols.get_symbol(i, name, value, size, bind, type, section, other);
|
||||
if(name == "tohost") {
|
||||
tohost = value;
|
||||
} else if(name == "fromhost") {
|
||||
fromhost = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sec->get_name() == ".tohost") {
|
||||
tohost = sec->get_address();
|
||||
fromhost = tohost + 0x40;
|
||||
}
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
return std::make_pair(entry_address, false);
|
||||
}
|
||||
|
||||
template <typename BASE>
|
||||
@ -626,17 +572,17 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
const unsigned length, uint8_t* const data) {
|
||||
#ifndef NDEBUG
|
||||
if(access && iss::access_type::DEBUG) {
|
||||
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else if(access && iss::access_type::FETCH) {
|
||||
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else {
|
||||
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
switch(space) {
|
||||
case traits<BASE>::MEM: {
|
||||
auto alignment = is_fetch(access) ? (traits<BASE>::MISA_VAL & 0x100 ? 2 : 4) : length;
|
||||
auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min<unsigned>(length, sizeof(reg_t));
|
||||
if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) {
|
||||
fault_data = addr;
|
||||
if(access && iss::access_type::DEBUG)
|
||||
@ -668,8 +614,10 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
}
|
||||
return res;
|
||||
} catch(trap_access& ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
} break;
|
||||
@ -707,8 +655,10 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
@ -720,23 +670,23 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
|
||||
switch(length) {
|
||||
case 8:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 4:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 2:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 1:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
default:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
@ -751,6 +701,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
}
|
||||
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
try {
|
||||
// TODO: There is no check for alignment
|
||||
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);
|
||||
if(vm.levels != 0) { // VM is active
|
||||
@ -773,40 +724,6 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
fault_data = ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
|
||||
if((paddr.val + length) > mem.size())
|
||||
return iss::Err;
|
||||
switch(paddr.val) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
return iss::Ok;
|
||||
case 0x10008000: { // HFROSC base, hfrosccfg reg
|
||||
auto& p = mem(paddr.val / mem.page_size);
|
||||
auto offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
if(x & 0x40)
|
||||
x |= 0x80; // hfroscrdy = 1 if hfroscen==1
|
||||
return iss::Ok;
|
||||
}
|
||||
case 0x10008008: { // HFROSC base, pllcfg reg
|
||||
auto& p = mem(paddr.val / mem.page_size);
|
||||
auto offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
x |= 0x80; // set pll lock upon writing
|
||||
return iss::Ok;
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::CSR: {
|
||||
if(length != sizeof(reg_t))
|
||||
@ -838,8 +755,10 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
@ -886,7 +805,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
|
||||
}
|
||||
|
||||
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->reg.cycle + cycle_offset;
|
||||
if(addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if(addr == mcycleh) {
|
||||
@ -907,7 +826,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsign
|
||||
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->reg.cycle; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -935,7 +854,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsi
|
||||
}
|
||||
|
||||
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->reg.cycle / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if(addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if(addr == timeh) {
|
||||
@ -1074,59 +993,52 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
|
||||
switch(paddr.val) {
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
break;
|
||||
default: {
|
||||
mem_type::page_type& p = mem(paddr.val / mem.page_size);
|
||||
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
||||
// tohost handling in case of riscv-test
|
||||
// according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754:
|
||||
if(paddr.access && iss::access_type::FUNC) {
|
||||
auto tohost_upper =
|
||||
(traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
if(tohost_lower || tohost_upper) {
|
||||
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
|
||||
if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
|
||||
switch(hostvar >> 48) {
|
||||
case 0:
|
||||
if(hostvar != 0x1) {
|
||||
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
if(paddr.val == tohost) {
|
||||
reg_t cur_data = *reinterpret_cast<const reg_t*>(data);
|
||||
// Extract Device (bits 63:56)
|
||||
uint8_t device = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 56) & 0xFF;
|
||||
// Extract Command (bits 55:48)
|
||||
uint8_t command = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 48) & 0xFF;
|
||||
// Extract payload (bits 47:0)
|
||||
uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL;
|
||||
if(payload_addr & 1) {
|
||||
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr
|
||||
<< "), stopping simulation";
|
||||
} else {
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = hostvar;
|
||||
break;
|
||||
// throw(iss::simulation_stopped(hostvar));
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if(c == '\n' || c == 0) {
|
||||
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else
|
||||
uart_buf << c;
|
||||
to_host_wr_cnt = 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
} else if(device == 0 && command == 0) {
|
||||
std::array<uint64_t, 8> loaded_payload;
|
||||
if(read(address_type::PHYSICAL, access_type::DEBUG_READ, traits<BASE>::MEM, payload_addr, 8 * sizeof(uint64_t),
|
||||
reinterpret_cast<uint8_t*>(loaded_payload.data())) == iss::Err)
|
||||
CPPLOG(ERR) << "Syscall read went wrong";
|
||||
uint64_t syscall_num = loaded_payload.at(0);
|
||||
if(syscall_num == 64) { // SYS_WRITE
|
||||
return execute_sys_write(this, loaded_payload, traits<BASE>::MEM);
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num
|
||||
<< ") not implemented";
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
} else if(tohost_lower)
|
||||
to_host_wr_cnt++;
|
||||
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost functionality not implemented for device " << device << " and command " << command;
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
}
|
||||
if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
uint64_t fhostvar = *reinterpret_cast<uint64_t*>(p.data() + (fromhost & mem.page_addr_mask));
|
||||
*reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -1304,6 +1216,31 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
// csr[dpc] = addr;
|
||||
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||
csr[utval | (new_priv << 8)] = addr;
|
||||
if(semihosting_cb) {
|
||||
// Check for semihosting call
|
||||
phys_addr_t p_addr(access_type::DEBUG_READ, traits<BASE>::MEM, addr - 4);
|
||||
std::array<uint8_t, 8> data;
|
||||
// check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07
|
||||
this->read_mem(p_addr, 4, data.data());
|
||||
p_addr.val += 8;
|
||||
this->read_mem(p_addr, 4, data.data() + 4);
|
||||
|
||||
const std::array<uint8_t, 8> ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40};
|
||||
if(data == ref_data) {
|
||||
this->reg.NEXT_PC = addr + 8;
|
||||
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
#else
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
#endif
|
||||
CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred ";
|
||||
|
||||
semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/);
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@ -1321,7 +1258,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
this->reg.pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << 31) + cause;
|
||||
csr[adr] = (trap_id << (traits<BASE>::XLEN - 1)) + cause;
|
||||
// update mstatus
|
||||
// xPP field of mstatus is written with the active privilege mode at the time
|
||||
// of the trap; the x PIE field of mstatus
|
||||
|
@ -39,7 +39,14 @@
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "iss/log_categories.h"
|
||||
#include "iss/vm_if.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include "riscv_hart_common.h"
|
||||
#include "util/logging.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <elfio/elf_types.hpp>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
@ -55,18 +62,13 @@
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
#include <iss/semihosting/semihosting.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_mu_p : public BASE {
|
||||
template <typename BASE, features_e FEAT = FEAT_NONE, typename LOGCAT = logging::disass>
|
||||
class riscv_hart_mu_p : public BASE, public riscv_hart_common {
|
||||
protected:
|
||||
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
const std::array<const char*, 16> trap_str = {{""
|
||||
@ -93,7 +95,7 @@ protected:
|
||||
|
||||
public:
|
||||
using core = BASE;
|
||||
using this_class = riscv_hart_mu_p<BASE, FEAT>;
|
||||
using this_class = riscv_hart_mu_p<BASE, FEAT, LOGCAT>;
|
||||
using phys_addr_t = typename core::phys_addr_t;
|
||||
using reg_t = typename core::reg_t;
|
||||
using addr_t = typename core::addr_t;
|
||||
@ -307,8 +309,8 @@ public:
|
||||
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus,
|
||||
this->reg.icount + cycle_offset);
|
||||
NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus,
|
||||
this->reg.cycle + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
|
||||
@ -317,10 +319,12 @@ public:
|
||||
|
||||
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
|
||||
|
||||
void set_semihosting_callback(semihosting_cb_t<reg_t> cb) { semihosting_cb = cb; };
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT>& arch)
|
||||
riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch)
|
||||
: arch(arch) {}
|
||||
/**
|
||||
* get the name of this architecture
|
||||
@ -339,7 +343,7 @@ protected:
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; }
|
||||
|
||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||
|
||||
@ -349,7 +353,9 @@ protected:
|
||||
|
||||
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
|
||||
|
||||
riscv_hart_mu_p<BASE, FEAT>& arch;
|
||||
std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
|
||||
|
||||
riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch;
|
||||
};
|
||||
|
||||
friend struct riscv_instrumentation_if;
|
||||
@ -369,17 +375,15 @@ protected:
|
||||
int64_t instret_offset{0};
|
||||
uint64_t minstret_csr{0};
|
||||
reg_t fault_data;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
uint64_t fromhost = fromhost_dflt;
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
riscv_instrumentation_if instr_if;
|
||||
|
||||
semihosting_cb_t<reg_t> semihosting_cb;
|
||||
|
||||
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
|
||||
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
|
||||
using csr_page_type = typename csr_type::page_type;
|
||||
mem_type mem;
|
||||
csr_type csr;
|
||||
std::stringstream uart_buf;
|
||||
std::unordered_map<reg_t, uint64_t> ptw;
|
||||
std::unordered_map<uint64_t, uint8_t> atomic_reservation;
|
||||
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
|
||||
@ -401,8 +405,8 @@ protected:
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
iss::status read_csr_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_csr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_plain(unsigned addr, reg_t& val);
|
||||
iss::status write_plain(unsigned addr, reg_t val);
|
||||
iss::status read_null(unsigned addr, reg_t& val);
|
||||
iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; }
|
||||
iss::status read_cycle(unsigned addr, reg_t& val);
|
||||
@ -425,15 +429,17 @@ protected:
|
||||
iss::status read_intstatus(unsigned addr, reg_t& val);
|
||||
iss::status write_intthresh(unsigned addr, reg_t val);
|
||||
iss::status write_xtvt(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_dcsr_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_dcsr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_dpc_reg(unsigned addr, reg_t& val);
|
||||
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
||||
iss::status write_pmpcfg_reg(unsigned addr, reg_t val);
|
||||
iss::status write_dcsr(unsigned addr, reg_t val);
|
||||
iss::status read_debug(unsigned addr, reg_t& val);
|
||||
iss::status write_dscratch(unsigned addr, reg_t val);
|
||||
iss::status read_dpc(unsigned addr, reg_t& val);
|
||||
iss::status write_dpc(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_pmpcfg(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; };
|
||||
virtual iss::status read_custom_csr(unsigned addr, reg_t& val) { return iss::status::Err; };
|
||||
virtual iss::status write_custom_csr(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; }
|
||||
@ -461,8 +467,8 @@ protected:
|
||||
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
: state()
|
||||
, instr_if(*this)
|
||||
, cfg(cfg) {
|
||||
@ -472,19 +478,22 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
|
||||
uart_buf.str("");
|
||||
if(traits<BASE>::FLEN > 0) {
|
||||
csr_rd_cb[fcsr] = &this_class::read_fcsr;
|
||||
csr_wr_cb[fcsr] = &this_class::write_fcsr;
|
||||
}
|
||||
for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
if(traits<BASE>::XLEN == 32)
|
||||
for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
@ -492,12 +501,11 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
if(traits<BASE>::XLEN == 32)
|
||||
for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) {
|
||||
csr_rd_cb[addr] = &this_class::read_null;
|
||||
// csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
}
|
||||
// common regs
|
||||
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
|
||||
for(auto addr : roaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[addr] = &this_class::read_plain;
|
||||
csr_wr_cb[addr] = &this_class::write_null;
|
||||
}
|
||||
const std::array<unsigned, 8> rwaddrs{{
|
||||
@ -511,8 +519,8 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
utval,
|
||||
}};
|
||||
for(auto addr : rwaddrs) {
|
||||
csr_rd_cb[addr] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[addr] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[addr] = &this_class::read_plain;
|
||||
csr_wr_cb[addr] = &this_class::write_plain;
|
||||
}
|
||||
// special handling & overrides
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
@ -557,18 +565,18 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
|
||||
if(FEAT & FEAT_PMP) {
|
||||
for(size_t i = pmpaddr0; i <= pmpaddr15; ++i) {
|
||||
csr_rd_cb[i] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[i] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[i] = &this_class::read_plain;
|
||||
csr_wr_cb[i] = &this_class::write_plain;
|
||||
}
|
||||
for(size_t i = pmpcfg0; i < pmpcfg0 + 16 / sizeof(reg_t); ++i) {
|
||||
csr_rd_cb[i] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
|
||||
csr_rd_cb[i] = &this_class::read_plain;
|
||||
csr_wr_cb[i] = &this_class::write_pmpcfg;
|
||||
}
|
||||
}
|
||||
if(FEAT & FEAT_EXT_N) {
|
||||
csr_rd_cb[mideleg] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[mideleg] = &this_class::read_plain;
|
||||
csr_wr_cb[mideleg] = &this_class::write_ideleg;
|
||||
csr_rd_cb[medeleg] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[medeleg] = &this_class::read_plain;
|
||||
csr_wr_cb[medeleg] = &this_class::write_edeleg;
|
||||
csr_rd_cb[uie] = &this_class::read_ie;
|
||||
csr_wr_cb[uie] = &this_class::write_ie;
|
||||
@ -582,7 +590,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
csr_rd_cb[utvec] = &this_class::read_tvec;
|
||||
}
|
||||
if(FEAT & FEAT_CLIC) {
|
||||
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[mtvt] = &this_class::read_plain;
|
||||
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;
|
||||
@ -592,14 +600,14 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
// 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_rd_cb[mintthresh] = &this_class::read_plain;
|
||||
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
|
||||
if(FEAT & FEAT_EXT_N) {
|
||||
csr_rd_cb[utvt] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[utvt] = &this_class::read_plain;
|
||||
csr_wr_cb[utvt] = &this_class::write_xtvt;
|
||||
csr_rd_cb[uintstatus] = &this_class::read_intstatus;
|
||||
csr_wr_cb[uintstatus] = &this_class::write_null;
|
||||
csr_rd_cb[uintthresh] = &this_class::read_csr_reg;
|
||||
csr_rd_cb[uintthresh] = &this_class::read_plain;
|
||||
csr_wr_cb[uintthresh] = &this_class::write_intthresh;
|
||||
}
|
||||
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0});
|
||||
@ -628,88 +636,33 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
|
||||
}
|
||||
if(FEAT & FEAT_DEBUG) {
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
|
||||
csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dpc] = &this_class::write_dpc_reg;
|
||||
csr_rd_cb[dpc] = &this_class::read_dpc_reg;
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dscratch;
|
||||
csr_rd_cb[dscratch0] = &this_class::read_debug;
|
||||
csr_wr_cb[dscratch1] = &this_class::write_dscratch;
|
||||
csr_rd_cb[dscratch1] = &this_class::read_debug;
|
||||
csr_wr_cb[dpc] = &this_class::write_dpc;
|
||||
csr_rd_cb[dpc] = &this_class::read_dpc;
|
||||
csr_wr_cb[dcsr] = &this_class::write_dcsr;
|
||||
csr_rd_cb[dcsr] = &this_class::read_debug;
|
||||
}
|
||||
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return this->read_mem(a, l, d); };
|
||||
hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return this->write_mem(a, l, d); };
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||
FILE* fp = fopen(name.c_str(), "r");
|
||||
if(fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
fclose(fp);
|
||||
if(n != 4)
|
||||
throw std::runtime_error("input file has insufficient size");
|
||||
buf[4] = 0;
|
||||
if(strcmp(buf.data() + 1, "ELF") == 0) {
|
||||
// Create elfio reader
|
||||
ELFIO::elfio reader;
|
||||
// Load ELF data
|
||||
if(!reader.load(name))
|
||||
throw std::runtime_error("could not process elf file");
|
||||
// check elf properties
|
||||
if(reader.get_class() != ELFCLASS32)
|
||||
if(sizeof(reg_t) == 4)
|
||||
throw std::runtime_error("wrong elf class in file");
|
||||
if(reader.get_type() != ET_EXEC)
|
||||
throw std::runtime_error("wrong elf type in file");
|
||||
if(reader.get_machine() != EM_RISCV)
|
||||
throw std::runtime_error("wrong elf machine in file");
|
||||
auto entry = reader.get_entry();
|
||||
for(const auto pseg : reader.segments) {
|
||||
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
|
||||
const auto seg_data = pseg->get_data();
|
||||
if(fsize > 0) {
|
||||
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
|
||||
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
|
||||
if(res != iss::Ok)
|
||||
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) {
|
||||
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64,
|
||||
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
|
||||
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size,
|
||||
data);
|
||||
})) {
|
||||
return std::make_pair(entry_address, true);
|
||||
}
|
||||
}
|
||||
for(const auto sec : reader.sections) {
|
||||
if(sec->get_name() == ".symtab") {
|
||||
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
|
||||
ELFIO::symbol_section_accessor symbols(reader, sec);
|
||||
auto sym_no = symbols.get_symbols_num();
|
||||
std::string name;
|
||||
ELFIO::Elf64_Addr value = 0;
|
||||
ELFIO::Elf_Xword size = 0;
|
||||
unsigned char bind = 0;
|
||||
unsigned char type = 0;
|
||||
ELFIO::Elf_Half section = 0;
|
||||
unsigned char other = 0;
|
||||
for(auto i = 0U; i < sym_no; ++i) {
|
||||
symbols.get_symbol(i, name, value, size, bind, type, section, other);
|
||||
if(name == "tohost") {
|
||||
tohost = value;
|
||||
} else if(name == "fromhost") {
|
||||
fromhost = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(sec->get_name() == ".tohost") {
|
||||
tohost = sec->get_address();
|
||||
fromhost = tohost + 0x40;
|
||||
}
|
||||
}
|
||||
return std::make_pair(entry, true);
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
|
||||
}
|
||||
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
|
||||
return std::make_pair(entry_address, false);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
inline void riscv_hart_mu_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
inline void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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(
|
||||
@ -721,13 +674,14 @@ inline void riscv_hart_mu_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_
|
||||
memfn_write.insert(std::begin(memfn_write) + idx, wr_fn);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
inline iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_pmpcfg(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & 0x9f9f9f9f;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
bool riscv_hart_mu_p<BASE, FEAT, LOGCAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
|
||||
constexpr auto PMP_SHIFT = 2U;
|
||||
constexpr auto PMP_R = 0x1U;
|
||||
constexpr auto PMP_W = 0x2U;
|
||||
@ -807,16 +761,16 @@ bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64
|
||||
return !any_active || this->reg.PRIV == PRIV_M;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read(const address_type type, const access_type access, const uint32_t space,
|
||||
const uint64_t addr, const unsigned length, uint8_t* const data) {
|
||||
#ifndef NDEBUG
|
||||
if(access && iss::access_type::DEBUG) {
|
||||
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else if(is_fetch(access)) {
|
||||
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else {
|
||||
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
@ -831,7 +785,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : length;
|
||||
auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min<unsigned>(length, sizeof(reg_t));
|
||||
if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) {
|
||||
fault_data = addr;
|
||||
if(is_debug(access))
|
||||
@ -866,8 +820,10 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
}
|
||||
return res;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
} break;
|
||||
@ -894,36 +850,38 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::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) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write(const address_type type, const access_type access, const uint32_t space,
|
||||
const uint64_t addr, const unsigned length, const uint8_t* const data) {
|
||||
#ifndef NDEBUG
|
||||
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
|
||||
switch(length) {
|
||||
case 8:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 4:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 2:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
case 1:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
|
||||
<< std::hex << addr;
|
||||
break;
|
||||
default:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
@ -946,7 +904,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length > 1 && (addr & (length - 1)) && (access & access_type::DEBUG) != access_type::DEBUG) {
|
||||
auto alignment = std::min<unsigned>(length, sizeof(reg_t));
|
||||
if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) {
|
||||
this->reg.trap_state = (1UL << 31) | 6 << 16;
|
||||
fault_data = addr;
|
||||
return iss::Err;
|
||||
@ -976,40 +935,6 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
fault_data = ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
|
||||
if((addr + length) > mem.size())
|
||||
return iss::Err;
|
||||
switch(addr) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
return iss::Ok;
|
||||
case 0x10008000: { // HFROSC base, hfrosccfg reg
|
||||
auto& p = mem(addr / mem.page_size);
|
||||
auto offs = addr & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
if(x & 0x40)
|
||||
x |= 0x80; // hfroscrdy = 1 if hfroscen==1
|
||||
return iss::Ok;
|
||||
}
|
||||
case 0x10008008: { // HFROSC base, pllcfg reg
|
||||
auto& p = mem(addr / mem.page_size);
|
||||
auto offs = addr & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto& x = *(p.data() + offs + 3);
|
||||
x |= 0x80; // set pll lock upon writing
|
||||
return iss::Ok;
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::CSR: {
|
||||
if(length != sizeof(reg_t))
|
||||
@ -1036,13 +961,16 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch(trap_access& ta) {
|
||||
if((access & access_type::DEBUG) == 0) {
|
||||
this->reg.trap_state = (1UL << 31) | ta.id;
|
||||
fault_data = ta.addr;
|
||||
}
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_csr(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t& val) {
|
||||
if(addr >= csr.size())
|
||||
return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
@ -1054,7 +982,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t val) {
|
||||
if(addr >= csr.size())
|
||||
return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
@ -1068,23 +997,27 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t& val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_null(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_null(unsigned addr, reg_t& val) {
|
||||
val = 0;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_csr_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_plain(unsigned addr, reg_t& val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_plain(unsigned addr, reg_t val) {
|
||||
csr[addr] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t& val) {
|
||||
auto cycle_val = this->reg.icount + cycle_offset;
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_cycle(unsigned addr, reg_t& val) {
|
||||
auto cycle_val = this->reg.cycle + cycle_offset;
|
||||
if(addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if(addr == mcycleh) {
|
||||
@ -1093,7 +1026,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_t val) {
|
||||
if(sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
mcycle_csr = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
@ -1103,11 +1037,12 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr - this->reg.icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg_t& val) {
|
||||
if((addr & 0xff) == (minstret & 0xff)) {
|
||||
val = static_cast<reg_t>(this->reg.instret);
|
||||
} else if((addr & 0xff) == (minstreth & 0xff)) {
|
||||
@ -1116,7 +1051,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, reg_t val) {
|
||||
if(sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
@ -1130,8 +1066,9 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t& val) {
|
||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_time(unsigned addr, reg_t& val) {
|
||||
uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if(addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if(addr == timeh) {
|
||||
@ -1142,22 +1079,27 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_tvec(unsigned addr, reg_t& val) {
|
||||
val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2;
|
||||
return iss::Ok;
|
||||
}
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t& val) {
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_status(unsigned addr, reg_t& val) {
|
||||
val = state.mstatus & hart_state_type::get_mask((addr >> 8) & 0x3);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_status(unsigned addr, reg_t val) {
|
||||
state.write_mstatus(val, (addr >> 8) & 0x3);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cause(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_cause(unsigned addr, reg_t& val) {
|
||||
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) {
|
||||
val = csr[addr] & ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
|
||||
auto mode = (addr >> 8) & 0x3;
|
||||
@ -1177,7 +1119,8 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_cause(unsigned addr, reg_t val) {
|
||||
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);
|
||||
@ -1200,12 +1143,14 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_hartid(unsigned addr, reg_t& val) {
|
||||
val = mhartid_reg;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ie(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ie(unsigned addr, reg_t& val) {
|
||||
auto mask = get_irq_mask((addr >> 8) & 0x3);
|
||||
val = csr[mie] & mask;
|
||||
if(this->reg.PRIV != 3)
|
||||
@ -1213,14 +1158,16 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_ie(unsigned addr, reg_t val) {
|
||||
auto mask = get_irq_mask((addr >> 8) & 0x3);
|
||||
csr[mie] = (csr[mie] & ~mask) | (val & mask);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ip(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ip(unsigned addr, reg_t& val) {
|
||||
auto mask = get_irq_mask((addr >> 8) & 0x3);
|
||||
val = csr[mip] & mask;
|
||||
if(this->reg.PRIV != 3)
|
||||
@ -1228,24 +1175,28 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ideleg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_ideleg(unsigned addr, reg_t val) {
|
||||
auto mask = 0b000100010001; // only U mode supported
|
||||
csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_edeleg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_edeleg(unsigned addr, reg_t val) {
|
||||
auto mask = 0b1011001111110111; // bit 14/10 (reserved), bit 11 (Env call), and 3 (break) are hardwired to 0
|
||||
csr[medeleg] = (csr[medeleg] & ~mask) | (val & mask);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_epc(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & get_pc_mask();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dcsr_dcsr(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
// +-------------- ebreakm
|
||||
@ -1256,35 +1207,40 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_debug(unsigned addr, reg_t& val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dscratch(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
csr[addr] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_dpc(unsigned addr, reg_t& val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
val = this->reg.DPC;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dpc(unsigned addr, reg_t val) {
|
||||
if(!debug_mode_active())
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
this->reg.DPC = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_intstatus(unsigned addr, reg_t& val) {
|
||||
auto mode = (addr >> 8) & 0x3;
|
||||
val = clic_uact_lvl & 0xff;
|
||||
if(mode == 0x3)
|
||||
@ -1292,18 +1248,32 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_fcsr(unsigned addr, reg_t& val) {
|
||||
val = this->get_fcsr();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_fcsr(unsigned addr, reg_t val) {
|
||||
this->set_fcsr(val);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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_mu_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_xtvt(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & ~0x3fULL;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
|
||||
switch(paddr.val) {
|
||||
default: {
|
||||
for(auto offs = 0U; offs < length; ++offs) {
|
||||
@ -1313,67 +1283,59 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
|
||||
switch(paddr.val) {
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else if(((char)data[0]) != '\r')
|
||||
uart_buf << (char)data[0];
|
||||
break;
|
||||
default: {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
|
||||
mem_type::page_type& p = mem(paddr.val / mem.page_size);
|
||||
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
||||
// tohost handling in case of riscv-test
|
||||
// according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754:
|
||||
if(paddr.access && iss::access_type::FUNC) {
|
||||
auto tohost_upper =
|
||||
(traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
if(tohost_lower || tohost_upper) {
|
||||
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
|
||||
if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
|
||||
switch(hostvar >> 48) {
|
||||
case 0:
|
||||
if(hostvar != 0x1) {
|
||||
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
if(paddr.val == tohost) {
|
||||
reg_t cur_data = *reinterpret_cast<const reg_t*>(data);
|
||||
// Extract Device (bits 63:56)
|
||||
uint8_t device = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 56) & 0xFF;
|
||||
// Extract Command (bits 55:48)
|
||||
uint8_t command = traits<BASE>::XLEN == 32 ? 0 : (cur_data >> 48) & 0xFF;
|
||||
// Extract payload (bits 47:0)
|
||||
uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL;
|
||||
if(payload_addr & 1) {
|
||||
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr
|
||||
<< "), stopping simulation";
|
||||
} else {
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = hostvar;
|
||||
break;
|
||||
// throw(iss::simulation_stopped(hostvar));
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if(c == '\n' || c == 0) {
|
||||
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else
|
||||
uart_buf << c;
|
||||
to_host_wr_cnt = 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
} else if(device == 0 && command == 0) {
|
||||
std::array<uint64_t, 8> loaded_payload;
|
||||
if(read(address_type::PHYSICAL, access_type::DEBUG_READ, traits<BASE>::MEM, payload_addr, 8 * sizeof(uint64_t),
|
||||
reinterpret_cast<uint8_t*>(loaded_payload.data())) == iss::Err)
|
||||
CPPLOG(ERR) << "Syscall read went wrong";
|
||||
uint64_t syscall_num = loaded_payload.at(0);
|
||||
if(syscall_num == 64) { // SYS_WRITE
|
||||
return execute_sys_write(this, loaded_payload, traits<BASE>::MEM);
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num
|
||||
<< ") not implemented";
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
} else if(tohost_lower)
|
||||
to_host_wr_cnt++;
|
||||
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
} else {
|
||||
CPPLOG(ERR) << "tohost functionality not implemented for device " << device << " and command " << command;
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = payload_addr;
|
||||
return iss::Ok;
|
||||
}
|
||||
}
|
||||
if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
uint64_t fhostvar = *reinterpret_cast<uint64_t*>(p.data() + (fromhost & mem.page_addr_mask));
|
||||
*reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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)
|
||||
@ -1392,8 +1354,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned lengt
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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
|
||||
@ -1408,12 +1370,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned leng
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT>::reset(uint64_t address) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT> inline void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::reset(uint64_t address) {
|
||||
BASE::reset(address);
|
||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::check_interrupt() {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT> void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::check_interrupt() {
|
||||
// TODO: Implement CLIC functionality
|
||||
auto ideleg = csr[mideleg];
|
||||
// Multiple simultaneous interrupts and traps at the same privilege level are
|
||||
@ -1436,7 +1398,8 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT>
|
||||
uint64_t riscv_hart_mu_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||
// calculate and write mcause val
|
||||
if(flags == std::numeric_limits<uint64_t>::max())
|
||||
@ -1474,6 +1437,31 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
} else {
|
||||
csr[utval | (new_priv << 8)] = addr;
|
||||
}
|
||||
if(semihosting_cb) {
|
||||
// Check for semihosting call
|
||||
phys_addr_t p_addr(access_type::DEBUG_READ, traits<BASE>::MEM, addr - 4);
|
||||
std::array<uint8_t, 8> data;
|
||||
// check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07
|
||||
this->read_mem(p_addr, 4, data.data());
|
||||
p_addr.val += 8;
|
||||
this->read_mem(p_addr, 4, data.data() + 4);
|
||||
|
||||
const std::array<uint8_t, 8> ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40};
|
||||
if(data == ref_data) {
|
||||
this->reg.NEXT_PC = addr + 8;
|
||||
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
#else
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
#endif
|
||||
CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred ";
|
||||
|
||||
semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/);
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@ -1545,7 +1533,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
|
||||
template <typename BASE, features_e FEAT, typename LOGCAT> uint64_t riscv_hart_mu_p<BASE, FEAT, LOGCAT>::leave_trap(uint64_t flags) {
|
||||
auto cur_priv = this->reg.PRIV;
|
||||
auto inst_priv = (flags & 0x3) ? 3 : 0;
|
||||
if(inst_priv > cur_priv) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* Copyright (C) 2024 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
File diff suppressed because one or more lines are too long
@ -87,7 +87,7 @@ public:
|
||||
virtual ~wt_cache() = default;
|
||||
|
||||
unsigned size{4096};
|
||||
unsigned line_sz{32};
|
||||
unsigned line_sz{64};
|
||||
unsigned ways{1};
|
||||
uint64_t io_address{0xf0000000};
|
||||
uint64_t io_addr_mask{0xf0000000};
|
||||
@ -119,7 +119,7 @@ template <typename BASE> iss::status iss::arch::wt_cache<BASE>::read_cache(phys_
|
||||
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) {
|
||||
if((a.access & iss::access_type::FETCH) == iss::access_type::FETCH || (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];
|
||||
|
4108
src/iss/debugger/csr_names.cpp
Normal file
4108
src/iss/debugger/csr_names.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,8 +30,8 @@
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_
|
||||
#define _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_
|
||||
#ifndef _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_
|
||||
#define _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_
|
||||
|
||||
#include "iss/arch_if.h"
|
||||
#include <iss/arch/traits.h>
|
||||
@ -48,6 +48,10 @@
|
||||
|
||||
namespace iss {
|
||||
namespace debugger {
|
||||
|
||||
char const* const get_csr_name(unsigned);
|
||||
constexpr auto csr_offset = 100U;
|
||||
|
||||
using namespace iss::arch;
|
||||
using namespace iss::debugger;
|
||||
|
||||
@ -129,11 +133,17 @@ public:
|
||||
|
||||
protected:
|
||||
static inline constexpr addr_t map_addr(const addr_t& i) { return i; }
|
||||
|
||||
std::string csr_xml;
|
||||
iss::arch_if* core;
|
||||
rp_thread_ref thread_idx;
|
||||
};
|
||||
|
||||
template <typename ARCH> typename std::enable_if<iss::arch::traits<ARCH>::FLEN != 0, unsigned>::type get_f0_offset() {
|
||||
return iss::arch::traits<ARCH>::F0;
|
||||
}
|
||||
|
||||
template <typename ARCH> typename std::enable_if<iss::arch::traits<ARCH>::FLEN == 0, unsigned>::type get_f0_offset() { return 0; }
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::set_gen_thread(rp_thread_ref& thread) {
|
||||
thread_idx = thread;
|
||||
return Ok;
|
||||
@ -174,13 +184,30 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::current_thread_query
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) {
|
||||
LOG(TRACE) << "reading target registers";
|
||||
// return idx<0?:;
|
||||
CPPLOG(TRACE) << "reading target registers";
|
||||
data.clear();
|
||||
avail.clear();
|
||||
const uint8_t* reg_base = core->get_regs_base_ptr();
|
||||
auto start_reg = arch::traits<ARCH>::X0;
|
||||
for(size_t reg_no = start_reg; reg_no < start_reg + 33 /*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
for(size_t i = 0; i < 33; ++i) {
|
||||
if(i < arch::traits<ARCH>::RFS || i == arch::traits<ARCH>::PC) {
|
||||
auto reg_no = i < 32 ? start_reg + i : arch::traits<ARCH>::PC;
|
||||
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
for(size_t j = 0; j < arch::traits<ARCH>::XLEN / 8; ++j) {
|
||||
data.push_back(*(reg_base + offset + j));
|
||||
avail.push_back(0xff);
|
||||
}
|
||||
} else {
|
||||
for(size_t j = 0; j < arch::traits<ARCH>::XLEN / 8; ++j) {
|
||||
data.push_back(0);
|
||||
avail.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(iss::arch::traits<ARCH>::FLEN > 0) {
|
||||
auto fstart_reg = get_f0_offset<ARCH>();
|
||||
for(size_t i = 0; i < 32; ++i) {
|
||||
auto reg_no = fstart_reg + i;
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
for(size_t j = 0; j < reg_width; ++j) {
|
||||
@ -188,21 +215,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::
|
||||
avail.push_back(0xff);
|
||||
}
|
||||
}
|
||||
// work around fill with F type registers
|
||||
// if (arch::traits<ARCH>::NUM_REGS < 65) {
|
||||
// auto reg_width = sizeof(typename arch::traits<ARCH>::reg_t);
|
||||
// for (size_t reg_no = 0; reg_no < 33; ++reg_no) {
|
||||
// for (size_t j = 0; j < reg_width; ++j) {
|
||||
// data.push_back(0x0);
|
||||
// avail.push_back(0x00);
|
||||
// }
|
||||
// // if(arch::traits<ARCH>::XLEN < 64)
|
||||
// // for(unsigned j=0; j<4; ++j){
|
||||
// // data.push_back(0x0);
|
||||
// // avail.push_back(0x00);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
||||
@ -210,25 +223,25 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
|
||||
auto start_reg = arch::traits<ARCH>::X0;
|
||||
auto* reg_base = core->get_regs_base_ptr();
|
||||
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) {
|
||||
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 iter_end = data.data() + data.size();
|
||||
for(size_t i = 0; i < 33 && iter < iter_end; ++i) {
|
||||
auto reg_width = arch::traits<ARCH>::XLEN / 8;
|
||||
if(i < arch::traits<ARCH>::RFS) {
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[start_reg + i];
|
||||
std::copy(iter, iter + reg_width, reg_base + offset);
|
||||
} else if(i == 32) {
|
||||
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);
|
||||
std::copy(iter, iter + reg_width, reg_base + offset);
|
||||
}
|
||||
} else {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
iter += 4;
|
||||
reg_base += offset;
|
||||
iter += reg_width;
|
||||
}
|
||||
if(iss::arch::traits<ARCH>::FLEN > 0) {
|
||||
auto fstart_reg = get_f0_offset<ARCH>();
|
||||
auto reg_width = arch::traits<ARCH>::FLEN / 8;
|
||||
for(size_t i = 0; i < 32 && iter < iter_end; ++i) {
|
||||
unsigned offset = traits<ARCH>::reg_byte_offsets[fstart_reg + i];
|
||||
std::copy(iter, iter + reg_width, reg_base + offset);
|
||||
iter += reg_width;
|
||||
}
|
||||
}
|
||||
return Ok;
|
||||
@ -236,7 +249,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
|
||||
|
||||
template <typename ARCH>
|
||||
status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std::vector<uint8_t>& data, std::vector<uint8_t>& avail) {
|
||||
if(reg_no < 65) {
|
||||
if(reg_no < csr_offset) {
|
||||
// auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename
|
||||
// arch::traits<ARCH>::reg_e>(reg_no))/8;
|
||||
auto* reg_base = core->get_regs_base_ptr();
|
||||
@ -247,23 +260,24 @@ status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std
|
||||
std::copy(reg_base + offset, reg_base + offset + reg_width, data.begin());
|
||||
std::fill(avail.begin(), avail.end(), 0xff);
|
||||
} else {
|
||||
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, reg_no - 65);
|
||||
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, reg_no - csr_offset);
|
||||
data.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||
avail.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||
std::fill(avail.begin(), avail.end(), 0xff);
|
||||
core->read(a, data.size(), data.data());
|
||||
std::fill(avail.begin(), avail.end(), 0xff);
|
||||
}
|
||||
return data.size() > 0 ? Ok : Err;
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::write_single_register(unsigned int reg_no, const std::vector<uint8_t>& data) {
|
||||
if(reg_no < 65) {
|
||||
if(reg_no < csr_offset) {
|
||||
auto* reg_base = core->get_regs_base_ptr();
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
|
||||
} else {
|
||||
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - 65);
|
||||
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - csr_offset);
|
||||
core->write(a, data.size(), data.data());
|
||||
}
|
||||
return Ok;
|
||||
@ -276,7 +290,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::read_mem(uint64_t ad
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::write_mem(uint64_t addr, const std::vector<uint8_t>& data) {
|
||||
auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
|
||||
auto a = map_addr({iss::access_type::DEBUG_WRITE, iss::address_type::VIRTUAL, 0, addr});
|
||||
auto f = [&]() -> status { return core->write(a, data.size(), data.data()); };
|
||||
return srv->execute_syncronized(f);
|
||||
}
|
||||
@ -328,9 +342,9 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(break_type
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
||||
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
||||
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val
|
||||
CPPLOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val
|
||||
<< std::dec;
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Ok;
|
||||
}
|
||||
}
|
||||
@ -345,13 +359,13 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(break_t
|
||||
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
||||
if(handle) {
|
||||
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec;
|
||||
CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec;
|
||||
// TODO: check length of addr range
|
||||
target_adapter_base::bp_lut.removeEntry(handle);
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Ok;
|
||||
}
|
||||
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
|
||||
return Err;
|
||||
}
|
||||
}
|
||||
@ -369,93 +383,57 @@ status riscv_target_adapter<ARCH>::resume_from_addr(bool step, int sig, uint64_t
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std::string& out_buf) {
|
||||
const std::string res{"<?xml version=\"1.0\"?><!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
|
||||
"<target><architecture>riscv:rv32</architecture>"
|
||||
//" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n"
|
||||
//" <reg name=\"x0\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x1\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x2\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x3\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x4\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x5\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x6\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x7\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x8\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x9\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x10\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x11\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x12\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x13\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x14\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x15\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x16\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x17\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x18\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x19\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x20\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x21\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x22\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x23\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x24\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x25\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x26\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x27\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x28\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x29\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x30\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" <reg name=\"x31\" bitsize=\"32\" group=\"general\"/>\n"
|
||||
//" </feature>\n"
|
||||
"</target>"};
|
||||
out_buf = res;
|
||||
if(!csr_xml.size()) {
|
||||
std::ostringstream oss;
|
||||
oss << "<?xml version=\"1.0\"?><!DOCTYPE feature SYSTEM \"gdb-target.dtd\"><target version=\"1.0\">\n";
|
||||
if(iss::arch::traits<ARCH>::XLEN == 32)
|
||||
oss << "<architecture>riscv:rv32</architecture>\n";
|
||||
else if(iss::arch::traits<ARCH>::XLEN == 64)
|
||||
oss << " <architectureriscv:rv64</architecture>\n";
|
||||
oss << " <feature name=\"org.gnu.gdb.riscv.cpu\">\n";
|
||||
auto reg_base_num = iss::arch::traits<ARCH>::X0;
|
||||
for(auto i = 0U; i < iss::arch::traits<ARCH>::RFS; ++i) {
|
||||
oss << " <reg name=\"x" << i << "\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[reg_base_num + i]
|
||||
<< "\" type=\"int\" regnum=\"" << i << "\"/>\n";
|
||||
}
|
||||
oss << " <reg name=\"pc\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[iss::arch::traits<ARCH>::PC]
|
||||
<< "\" type=\"code_ptr\" regnum=\"" << 32U << "\"/>\n";
|
||||
oss << " </feature>\n";
|
||||
if(iss::arch::traits<ARCH>::FLEN > 0) {
|
||||
oss << " <feature name=\"org.gnu.gdb.riscv.fpu\">\n";
|
||||
auto reg_base_num = get_f0_offset<ARCH>();
|
||||
auto type = iss::arch::traits<ARCH>::FLEN == 32 ? "ieee_single" : "riscv_double";
|
||||
for(auto i = 0U; i < 32; ++i) {
|
||||
oss << " <reg name=\"f" << i << "\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[reg_base_num + i]
|
||||
<< "\" type=\"" << type << "\" regnum=\"" << i + 33 << "\"/>\n";
|
||||
}
|
||||
oss << " <reg name=\"fcsr\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"103\" type int/>\n";
|
||||
oss << " <reg name=\"fflags\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"101\" type int/>\n";
|
||||
oss << " <reg name=\"frm\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"102\" type int/>\n";
|
||||
oss << " </feature>\n";
|
||||
}
|
||||
oss << " <feature name=\"org.gnu.gdb.riscv.csr\">\n";
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<uint8_t> avail;
|
||||
data.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||
avail.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||
for(auto i = 0U; i < 4096; ++i) {
|
||||
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, i);
|
||||
std::fill(avail.begin(), avail.end(), 0xff);
|
||||
auto res = core->read(a, data.size(), data.data());
|
||||
if(res == iss::Ok) {
|
||||
oss << " <reg name=\"" << get_csr_name(i) << "\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN
|
||||
<< "\" type=\"int\" regnum=\"" << (i + csr_offset) << "\"/>\n";
|
||||
}
|
||||
}
|
||||
oss << " </feature>\n";
|
||||
oss << "</target>\n";
|
||||
csr_xml = oss.str();
|
||||
}
|
||||
out_buf = csr_xml;
|
||||
return Ok;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target>
|
||||
<architecture>riscv:rv32</architecture>
|
||||
|
||||
<feature name="org.gnu.gdb.riscv.rv32i">
|
||||
<reg name="x0" bitsize="32" group="general"/>
|
||||
<reg name="x1" bitsize="32" group="general"/>
|
||||
<reg name="x2" bitsize="32" group="general"/>
|
||||
<reg name="x3" bitsize="32" group="general"/>
|
||||
<reg name="x4" bitsize="32" group="general"/>
|
||||
<reg name="x5" bitsize="32" group="general"/>
|
||||
<reg name="x6" bitsize="32" group="general"/>
|
||||
<reg name="x7" bitsize="32" group="general"/>
|
||||
<reg name="x8" bitsize="32" group="general"/>
|
||||
<reg name="x9" bitsize="32" group="general"/>
|
||||
<reg name="x10" bitsize="32" group="general"/>
|
||||
<reg name="x11" bitsize="32" group="general"/>
|
||||
<reg name="x12" bitsize="32" group="general"/>
|
||||
<reg name="x13" bitsize="32" group="general"/>
|
||||
<reg name="x14" bitsize="32" group="general"/>
|
||||
<reg name="x15" bitsize="32" group="general"/>
|
||||
<reg name="x16" bitsize="32" group="general"/>
|
||||
<reg name="x17" bitsize="32" group="general"/>
|
||||
<reg name="x18" bitsize="32" group="general"/>
|
||||
<reg name="x19" bitsize="32" group="general"/>
|
||||
<reg name="x20" bitsize="32" group="general"/>
|
||||
<reg name="x21" bitsize="32" group="general"/>
|
||||
<reg name="x22" bitsize="32" group="general"/>
|
||||
<reg name="x23" bitsize="32" group="general"/>
|
||||
<reg name="x24" bitsize="32" group="general"/>
|
||||
<reg name="x25" bitsize="32" group="general"/>
|
||||
<reg name="x26" bitsize="32" group="general"/>
|
||||
<reg name="x27" bitsize="32" group="general"/>
|
||||
<reg name="x28" bitsize="32" group="general"/>
|
||||
<reg name="x29" bitsize="32" group="general"/>
|
||||
<reg name="x30" bitsize="32" group="general"/>
|
||||
<reg name="x31" bitsize="32" group="general"/>
|
||||
</feature>
|
||||
|
||||
</target>
|
||||
|
||||
*/
|
||||
} // namespace debugger
|
||||
} // namespace iss
|
||||
|
||||
#endif /* _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */
|
||||
#endif /* _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */
|
||||
|
@ -61,7 +61,7 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
try {
|
||||
auto root = YAML::LoadAll(is);
|
||||
if(root.size() != 1) {
|
||||
LOG(ERR) << "Too many root nodes in YAML file " << config_file_name;
|
||||
CPPLOG(ERR) << "Too many root nodes in YAML file " << config_file_name;
|
||||
}
|
||||
for(auto p : root[0]) {
|
||||
auto isa_subset = p.first;
|
||||
@ -87,11 +87,11 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
}
|
||||
}
|
||||
} catch(YAML::ParserException& e) {
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(ERR) << "Could not open input file " << config_file_name;
|
||||
CPPLOG(ERR) << "Could not open input file " << config_file_name;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
|
||||
try {
|
||||
auto root = YAML::LoadAll(is);
|
||||
if(root.size() != 1) {
|
||||
LOG(ERR) << "Too many rro nodes in YAML file " << config_file_name;
|
||||
CPPLOG(ERR) << "Too many rro nodes in YAML file " << config_file_name;
|
||||
}
|
||||
for(auto p : root[0]) {
|
||||
auto isa_subset = p.first;
|
||||
@ -69,10 +69,10 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
|
||||
}
|
||||
rep_counts.resize(delays.size());
|
||||
} catch(YAML::ParserException& e) {
|
||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
||||
}
|
||||
} else {
|
||||
LOG(ERR) << "Could not open input file " << config_file_name;
|
||||
CPPLOG(ERR) << "Could not open input file " << config_file_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,7 +81,7 @@ iss::plugin::instruction_count::~instruction_count() {
|
||||
size_t idx = 0;
|
||||
for(auto it : delays) {
|
||||
if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0))
|
||||
LOG(INFO) << it.instr_name << ";" << rep_counts[idx];
|
||||
CPPLOG(INFO) << it.instr_name << ";" << rep_counts[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
297
src/iss/semihosting/semihosting.cpp
Normal file
297
src/iss/semihosting/semihosting.cpp
Normal file
@ -0,0 +1,297 @@
|
||||
#include "semihosting.h"
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <iss/vm_types.h>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
// explanation of syscalls can be found at https://github.com/SpinalHDL/openocd_riscv/blob/riscv_spinal/src/target/semihosting_common.h
|
||||
|
||||
const char* SYS_OPEN_MODES_STRS[] = {"r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b"};
|
||||
|
||||
template <typename T> T sh_read_field(iss::arch_if* arch_if_ptr, T addr, int len = 4) {
|
||||
uint8_t bytes[4];
|
||||
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr, 4, &bytes[0]);
|
||||
// auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
|
||||
|
||||
if(res != iss::Ok) {
|
||||
return 0; // TODO THROW ERROR
|
||||
} else
|
||||
return static_cast<T>(bytes[0]) | (static_cast<T>(bytes[1]) << 8) | (static_cast<T>(bytes[2]) << 16) |
|
||||
(static_cast<T>(bytes[3]) << 24);
|
||||
}
|
||||
|
||||
template <typename T> std::string sh_read_string(iss::arch_if* arch_if_ptr, T addr, T str_len) {
|
||||
std::vector<uint8_t> buffer(str_len);
|
||||
for(int i = 0; i < str_len; i++) {
|
||||
buffer[i] = sh_read_field(arch_if_ptr, addr + i, 1);
|
||||
}
|
||||
std::string str(buffer.begin(), buffer.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T> void semihosting_callback<T>::operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter) {
|
||||
static std::map<T, FILE*> openFiles;
|
||||
static T file_count = 3;
|
||||
static T semihostingErrno;
|
||||
|
||||
switch(static_cast<semihosting_syscalls>(*call_number)) {
|
||||
case semihosting_syscalls::SYS_CLOCK: {
|
||||
auto end = std::chrono::high_resolution_clock::now(); // end measurement
|
||||
auto elapsed = end - timeVar;
|
||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
|
||||
*call_number = millis; // TODO get time now
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_CLOSE: {
|
||||
T file_handle = *parameter;
|
||||
if(openFiles.size() <= file_handle && file_handle < 0) {
|
||||
semihostingErrno = EBADF;
|
||||
return;
|
||||
}
|
||||
auto file = openFiles[file_handle];
|
||||
openFiles.erase(file_handle);
|
||||
if(!(file == stdin || file == stdout || file == stderr)) {
|
||||
int i = fclose(file);
|
||||
*call_number = i;
|
||||
} else {
|
||||
*call_number = -1;
|
||||
semihostingErrno = EINTR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ELAPSED: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ERRNO: {
|
||||
*call_number = semihostingErrno;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_EXIT: {
|
||||
|
||||
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_EXIT_EXTENDED: {
|
||||
throw std::runtime_error("ISS terminated by Semihost: SYS_EXIT_EXTENDED");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_FLEN: {
|
||||
T file_handle = *parameter;
|
||||
auto file = openFiles[file_handle];
|
||||
|
||||
size_t currentPos = ftell(file);
|
||||
if(currentPos < 0)
|
||||
throw std::runtime_error("SYS_FLEN negative value");
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t length = ftell(file);
|
||||
fseek(file, currentPos, SEEK_SET);
|
||||
*call_number = (T)length;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_GET_CMDLINE: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_HEAPINFO: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ISERROR: {
|
||||
T value = *parameter;
|
||||
*call_number = (value != 0);
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_ISTTY: {
|
||||
T file_handle = *parameter;
|
||||
*call_number = (file_handle == 0 || file_handle == 1 || file_handle == 2);
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_OPEN: {
|
||||
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T mode = sh_read_field<T>(arch_if_ptr, 4 + (*parameter));
|
||||
T path_len = sh_read_field<T>(arch_if_ptr, 8 + (*parameter));
|
||||
|
||||
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
|
||||
|
||||
// TODO LOG INFO
|
||||
|
||||
if(mode >= 12) {
|
||||
// TODO throw ERROR
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* file = nullptr;
|
||||
if(path_str == ":tt") {
|
||||
if(mode < 4)
|
||||
file = stdin;
|
||||
else if(mode < 8)
|
||||
file = stdout;
|
||||
else
|
||||
file = stderr;
|
||||
} else {
|
||||
file = fopen(path_str.c_str(), SYS_OPEN_MODES_STRS[mode]);
|
||||
if(file == nullptr) {
|
||||
// TODO throw error
|
||||
return;
|
||||
}
|
||||
}
|
||||
T file_handle = file_count++;
|
||||
openFiles[file_handle] = file;
|
||||
*call_number = file_handle;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_READ: {
|
||||
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
|
||||
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T count = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
|
||||
|
||||
auto file = openFiles[file_handle];
|
||||
|
||||
std::vector<uint8_t> buffer(count);
|
||||
size_t num_read = 0;
|
||||
if(file == stdin) {
|
||||
// when reading from stdin: mimic behaviour from read syscall
|
||||
// and return on newline.
|
||||
while(num_read < count) {
|
||||
char c = fgetc(file);
|
||||
buffer[num_read] = c;
|
||||
num_read++;
|
||||
if(c == '\n')
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
num_read = fread(buffer.data(), 1, count, file);
|
||||
}
|
||||
buffer.resize(num_read);
|
||||
for(int i = 0; i < num_read; i++) {
|
||||
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, addr + i, 1, &buffer[i]);
|
||||
if(res != iss::Ok)
|
||||
return;
|
||||
}
|
||||
*call_number = count - num_read;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_READC: {
|
||||
uint8_t character = getchar();
|
||||
// character = getchar();
|
||||
/*if(character != iss::Ok)
|
||||
std::cout << "Not OK";
|
||||
return;*/
|
||||
*call_number = character;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_REMOVE: {
|
||||
T path_str_addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T path_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
|
||||
std::string path_str = sh_read_string<T>(arch_if_ptr, path_str_addr, path_len);
|
||||
|
||||
if(remove(path_str.c_str()) < 0)
|
||||
*call_number = -1;
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_RENAME: {
|
||||
T path_str_addr_old = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T path_len_old = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
|
||||
T path_str_addr_new = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
|
||||
T path_len_new = sh_read_field<T>(arch_if_ptr, (*parameter) + 12);
|
||||
|
||||
std::string path_str_old = sh_read_string<T>(arch_if_ptr, path_str_addr_old, path_len_old);
|
||||
std::string path_str_new = sh_read_string<T>(arch_if_ptr, path_str_addr_new, path_len_new);
|
||||
rename(path_str_old.c_str(), path_str_new.c_str());
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_SEEK: {
|
||||
T file_handle = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T pos = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
|
||||
auto file = openFiles[file_handle];
|
||||
|
||||
int retval = fseek(file, pos, SEEK_SET);
|
||||
if(retval < 0)
|
||||
throw std::runtime_error("SYS_SEEK negative return value");
|
||||
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_SYSTEM: {
|
||||
T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
|
||||
std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len);
|
||||
system(cmd.c_str());
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_TICKFREQ: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_TIME: {
|
||||
// returns time in seconds scince 01.01.1970 00:00
|
||||
*call_number = time(NULL);
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_TMPNAM: {
|
||||
T buffer_addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T identifier = sh_read_field<T>(arch_if_ptr, (*parameter) + 1);
|
||||
T buffer_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 2);
|
||||
|
||||
if(identifier > 255) {
|
||||
*call_number = -1;
|
||||
return;
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << "tmp/file-" << std::setfill('0') << std::setw(3) << identifier;
|
||||
std::string filename = ss.str();
|
||||
|
||||
for(int i = 0; i < buffer_len; i++) {
|
||||
uint8_t character = filename[i];
|
||||
auto res = arch_if_ptr->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, (*parameter) + i, 1, &character);
|
||||
if(res != iss::Ok)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_WRITE: {
|
||||
T file_handle = sh_read_field<T>(arch_if_ptr, (*parameter) + 4);
|
||||
T addr = sh_read_field<T>(arch_if_ptr, *parameter);
|
||||
T count = sh_read_field<T>(arch_if_ptr, (*parameter) + 8);
|
||||
|
||||
auto file = openFiles[file_handle];
|
||||
std::string str = sh_read_string<T>(arch_if_ptr, addr, count);
|
||||
fwrite(&str[0], 1, count, file);
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_WRITEC: {
|
||||
uint8_t character;
|
||||
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
|
||||
if(res != iss::Ok)
|
||||
return;
|
||||
putchar(character);
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::SYS_WRITE0: {
|
||||
uint8_t character;
|
||||
while(1) {
|
||||
auto res = arch_if_ptr->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0, *parameter, 1, &character);
|
||||
if(res != iss::Ok)
|
||||
return;
|
||||
if(character == 0)
|
||||
break;
|
||||
putchar(character);
|
||||
(*parameter)++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::USER_CMD_0x100: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
case semihosting_syscalls::USER_CMD_0x1FF: {
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Semihosting Call not Implemented");
|
||||
break;
|
||||
}
|
||||
}
|
||||
template class semihosting_callback<uint32_t>;
|
||||
template class semihosting_callback<uint64_t>;
|
61
src/iss/semihosting/semihosting.h
Normal file
61
src/iss/semihosting/semihosting.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _SEMIHOSTING_H_
|
||||
#define _SEMIHOSTING_H_
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iss/arch_if.h>
|
||||
/*
|
||||
* According to:
|
||||
* "Semihosting for AArch32 and AArch64, Release 2.0"
|
||||
* https://static.docs.arm.com/100863/0200/semihosting.pdf
|
||||
* from ARM Ltd.
|
||||
*
|
||||
* The available semihosting operation numbers passed in A0 are allocated
|
||||
* as follows:
|
||||
* - 0x00-0x31 Used by ARM.
|
||||
* - 0x32-0xFF Reserved for future use by ARM.
|
||||
* - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
|
||||
* However, if you are writing your own SVC operations, you are advised
|
||||
* to use a different SVC number rather than using the semihosted
|
||||
* SVC number and these operation type numbers.
|
||||
* - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
|
||||
* that you do not use these.
|
||||
*/
|
||||
enum class semihosting_syscalls {
|
||||
|
||||
SYS_OPEN = 0x01,
|
||||
SYS_CLOSE = 0x02,
|
||||
SYS_WRITEC = 0x03,
|
||||
SYS_WRITE0 = 0x04,
|
||||
SYS_WRITE = 0x05,
|
||||
SYS_READ = 0x06,
|
||||
SYS_READC = 0x07,
|
||||
SYS_ISERROR = 0x08,
|
||||
SYS_ISTTY = 0x09,
|
||||
SYS_SEEK = 0x0A,
|
||||
SYS_FLEN = 0x0C,
|
||||
SYS_TMPNAM = 0x0D,
|
||||
SYS_REMOVE = 0x0E,
|
||||
SYS_RENAME = 0x0F,
|
||||
SYS_CLOCK = 0x10,
|
||||
SYS_TIME = 0x11,
|
||||
SYS_SYSTEM = 0x12,
|
||||
SYS_ERRNO = 0x13,
|
||||
SYS_GET_CMDLINE = 0x15,
|
||||
SYS_HEAPINFO = 0x16,
|
||||
SYS_EXIT = 0x18,
|
||||
SYS_EXIT_EXTENDED = 0x20,
|
||||
SYS_ELAPSED = 0x30,
|
||||
SYS_TICKFREQ = 0x31,
|
||||
USER_CMD_0x100 = 0x100,
|
||||
USER_CMD_0x1FF = 0x1FF,
|
||||
};
|
||||
|
||||
template <typename T> struct semihosting_callback {
|
||||
std::chrono::high_resolution_clock::time_point timeVar;
|
||||
semihosting_callback()
|
||||
: timeVar(std::chrono::high_resolution_clock::now()) {}
|
||||
void operator()(iss::arch_if* arch_if_ptr, T* call_number, T* parameter);
|
||||
};
|
||||
|
||||
template <typename T> using semihosting_cb_t = std::function<void(iss::arch_if*, T*, T*)>;
|
||||
#endif
|
80
src/main.cpp
80
src/main.cpp
@ -31,8 +31,12 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iss/factory.h>
|
||||
#include <iss/semihosting/semihosting.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "iss/arch/tgc_mapper.h"
|
||||
@ -52,7 +56,6 @@
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
@ -66,13 +69,14 @@ int main(int argc, char* argv[]) {
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||
("ilimit,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||
("flimit", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of fetches to simulate")
|
||||
("reset,r", po::value<std::string>(), "reset address")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||
("mem,m", po::value<std::string>(), "the memory input file")
|
||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||
("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc")
|
||||
("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, llvm, tcc, asmjit")
|
||||
("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list");
|
||||
// clang-format on
|
||||
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
@ -116,6 +120,8 @@ int main(int argc, char* argv[]) {
|
||||
// instantiate the simulator
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
semihosting_callback<uint32_t> cb{};
|
||||
semihosting_cb_t<uint32_t> semihosting_cb = [&cb](iss::arch_if* i, uint32_t* a0, uint32_t* a1) { cb(i, a0, a1); };
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if(isa_opt.size() == 0 || isa_opt == "?") {
|
||||
auto list = f.get_names();
|
||||
@ -123,7 +129,8 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Available implementations (core|platform|backend):\n - " << util::join(list, "\n - ") << std::endl;
|
||||
return 0;
|
||||
} else if(isa_opt.find('|') != std::string::npos) {
|
||||
std::tie(cpu, vm) = f.create(isa_opt + "|" + clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
std::tie(cpu, vm) =
|
||||
f.create(isa_opt + "|" + clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>(), &semihosting_cb);
|
||||
} else {
|
||||
auto base_isa = isa_opt.substr(0, 5);
|
||||
if(base_isa == "tgc5d" || base_isa == "tgc5e") {
|
||||
@ -131,14 +138,17 @@ int main(int argc, char* argv[]) {
|
||||
} else {
|
||||
isa_opt += "|m_p|" + clim["backend"].as<std::string>();
|
||||
}
|
||||
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>());
|
||||
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>(), &semihosting_cb);
|
||||
}
|
||||
if(!cpu) {
|
||||
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
|
||||
auto list = f.get_names();
|
||||
std::sort(std::begin(list), std::end(list));
|
||||
CPPLOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << "\n"
|
||||
<< "Available implementations (core|platform|backend):\n - " << util::join(list, "\n - ") << 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;
|
||||
CPPLOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
|
||||
return 127;
|
||||
}
|
||||
if(clim.count("plugin")) {
|
||||
@ -174,7 +184,7 @@ int main(int argc, char* argv[]) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
CPPLOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
@ -198,24 +208,70 @@ int main(int argc, char* argv[]) {
|
||||
auto start_addr = vm->get_arch()->load_file(input);
|
||||
if(start_addr.second)
|
||||
start_address = start_addr.first;
|
||||
else {
|
||||
LOG(ERR) << "Error occured while loading file " << input << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for(std::string input : args) {
|
||||
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
|
||||
if(start_addr.second)
|
||||
start_address = start_addr.first;
|
||||
else {
|
||||
LOG(ERR) << "Error occured while loading file " << input << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(clim.count("reset")) {
|
||||
auto str = clim["reset"].as<std::string>();
|
||||
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
|
||||
}
|
||||
vm->reset(start_address);
|
||||
auto cycles = clim["instructions"].as<uint64_t>();
|
||||
res = vm->start(cycles, dump);
|
||||
auto limit = clim["ilimit"].as<uint64_t>();
|
||||
auto cond = iss::finish_cond_e::JUMP_TO_SELF;
|
||||
if(clim.count("flimit")) {
|
||||
cond = cond | iss::finish_cond_e::FCOUNT_LIMIT;
|
||||
limit = clim["flimit"].as<uint64_t>();
|
||||
} else {
|
||||
cond = cond | iss::finish_cond_e::ICOUNT_LIMIT;
|
||||
}
|
||||
res = vm->start(limit, dump, cond);
|
||||
|
||||
auto instr_if = vm->get_arch()->get_instrumentation_if();
|
||||
// this assumes a single input file
|
||||
std::unordered_map<std::string, uint64_t> sym_table;
|
||||
if(args.empty())
|
||||
sym_table = instr_if->get_symbol_table(clim["elf"].as<std::vector<std::string>>()[0]);
|
||||
else
|
||||
sym_table = instr_if->get_symbol_table(args[0]);
|
||||
if(sym_table.find("begin_signature") != std::end(sym_table) && sym_table.find("end_signature") != std::end(sym_table)) {
|
||||
auto start_addr = sym_table["begin_signature"];
|
||||
auto end_addr = sym_table["end_signature"];
|
||||
std::array<uint8_t, 4> data;
|
||||
std::ofstream file;
|
||||
std::string filename = fmt::format("{}.signature", isa_opt);
|
||||
std::replace(std::begin(filename), std::end(filename), '|', '_');
|
||||
// default riscof requires this filename
|
||||
filename = "DUT-tgc.signature";
|
||||
file.open(filename, std::ios::out);
|
||||
if(!file.is_open()) {
|
||||
LOG(ERR) << "Error opening file " << filename << std::endl;
|
||||
return 1;
|
||||
}
|
||||
for(auto addr = start_addr; addr < end_addr; addr += data.size()) {
|
||||
vm->get_arch()->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0 /*MEM*/, addr, data.size(),
|
||||
data.data()); // FIXME: get space from iss::arch::traits<ARCH>::mem_type_e::MEM
|
||||
|
||||
// TODO : obey Target endianess
|
||||
uint32_t to_print = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
|
||||
file << std::hex << fmt::format("{:08x}", to_print) << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl;
|
||||
CPPLOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl;
|
||||
res = 2;
|
||||
}
|
||||
// cleanup to let plugins report of needed
|
||||
// cleanup to let plugins report if needed
|
||||
for(auto* p : plugin_list) {
|
||||
delete p;
|
||||
}
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include <iss/plugin/loader.h>
|
||||
#endif
|
||||
#include "sc_core_adapter_if.h"
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include <iostream>
|
||||
@ -125,7 +124,7 @@ using vm_ptr = std::unique_ptr<iss::vm_if>;
|
||||
|
||||
class core_wrapper {
|
||||
public:
|
||||
core_wrapper(core_complex* owner)
|
||||
core_wrapper(core_complex_if* owner)
|
||||
: owner(owner) {}
|
||||
|
||||
void reset(uint64_t addr) { vm->reset(addr); }
|
||||
@ -181,7 +180,7 @@ public:
|
||||
"SystemC sub-commands: break <time>, print_time"});
|
||||
}
|
||||
|
||||
core_complex* const owner;
|
||||
core_complex_if* const owner;
|
||||
vm_ptr vm{nullptr};
|
||||
sc_cpu_ptr cpu{nullptr};
|
||||
iss::debugger::target_adapter_if* tgt_adapter{nullptr};
|
||||
@ -197,9 +196,9 @@ struct core_trace {
|
||||
scv_tr_handle tr_handle;
|
||||
};
|
||||
|
||||
SC_HAS_PROCESS(core_complex); // NOLINT
|
||||
#ifndef CWR_SYSTEMC
|
||||
core_complex::core_complex(sc_module_name const& name)
|
||||
template <unsigned int BUSWIDTH>
|
||||
core_complex<BUSWIDTH>::core_complex(sc_module_name const& name)
|
||||
: sc_module(name)
|
||||
, fetch_lut(tlm_dmi_ext())
|
||||
, read_lut(tlm_dmi_ext())
|
||||
@ -208,7 +207,7 @@ core_complex::core_complex(sc_module_name const& name)
|
||||
}
|
||||
#endif
|
||||
|
||||
void core_complex::init() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::init() {
|
||||
trc = new core_trace();
|
||||
ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
|
||||
auto lut_entry = fetch_lut.getEntry(start);
|
||||
@ -227,6 +226,7 @@ void core_complex::init() {
|
||||
}
|
||||
});
|
||||
|
||||
SC_HAS_PROCESS(core_complex<BUSWIDTH>); // NOLINT
|
||||
SC_THREAD(run);
|
||||
SC_METHOD(rst_cb);
|
||||
sensitive << rst_i;
|
||||
@ -252,16 +252,16 @@ void core_complex::init() {
|
||||
#endif
|
||||
}
|
||||
|
||||
core_complex::~core_complex() {
|
||||
template <unsigned int BUSWIDTH> core_complex<BUSWIDTH>::~core_complex() {
|
||||
delete cpu;
|
||||
delete trc;
|
||||
for(auto* p : plugin_list)
|
||||
delete p;
|
||||
}
|
||||
|
||||
void core_complex::trace(sc_trace_file* trf) const {}
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::trace(sc_trace_file* trf) const {}
|
||||
|
||||
void core_complex::before_end_of_elaboration() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::before_end_of_elaboration() {
|
||||
SCCDEBUG(SCMOD) << "instantiating iss::arch::tgf with " << GET_PROP_VALUE(backend) << " backend";
|
||||
// cpu = scc::make_unique<core_wrapper>(this);
|
||||
cpu = new core_wrapper(this);
|
||||
@ -302,7 +302,7 @@ void core_complex::before_end_of_elaboration() {
|
||||
}
|
||||
}
|
||||
|
||||
void core_complex::start_of_simulation() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::start_of_simulation() {
|
||||
// quantum_keeper.reset();
|
||||
if(GET_PROP_VALUE(elf_file).size() > 0) {
|
||||
istringstream is(GET_PROP_VALUE(elf_file));
|
||||
@ -325,7 +325,7 @@ void core_complex::start_of_simulation() {
|
||||
}
|
||||
}
|
||||
|
||||
bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
if(trc->m_db == nullptr)
|
||||
return false;
|
||||
if(trc->tr_handle.is_active())
|
||||
@ -339,7 +339,7 @@ bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void core_complex::forward() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::forward() {
|
||||
#ifndef CWR_SYSTEMC
|
||||
set_clock_period(clk_i.read());
|
||||
#else
|
||||
@ -348,24 +348,24 @@ void core_complex::forward() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void core_complex::set_clock_period(sc_core::sc_time period) {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::set_clock_period(sc_core::sc_time period) {
|
||||
curr_clk = period;
|
||||
if(period == SC_ZERO_TIME)
|
||||
cpu->set_interrupt_execution(true);
|
||||
}
|
||||
|
||||
void core_complex::rst_cb() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::rst_cb() {
|
||||
if(rst_i.read())
|
||||
cpu->set_interrupt_execution(true);
|
||||
}
|
||||
|
||||
void core_complex::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); }
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); }
|
||||
|
||||
void core_complex::timer_irq_cb() { cpu->local_irq(7, timer_irq_i.read()); }
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::timer_irq_cb() { cpu->local_irq(7, timer_irq_i.read()); }
|
||||
|
||||
void core_complex::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); }
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); }
|
||||
|
||||
void core_complex::local_irq_cb() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::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());
|
||||
@ -373,7 +373,7 @@ void core_complex::local_irq_cb() {
|
||||
}
|
||||
}
|
||||
|
||||
void core_complex::run() {
|
||||
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::run() {
|
||||
wait(SC_ZERO_TIME); // separate from elaboration phase
|
||||
do {
|
||||
wait(SC_ZERO_TIME);
|
||||
@ -391,7 +391,7 @@ void core_complex::run() {
|
||||
sc_stop();
|
||||
}
|
||||
|
||||
bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) {
|
||||
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) {
|
||||
auto& dmi_lut = is_fetch ? fetch_lut : read_lut;
|
||||
auto lut_entry = dmi_lut.getEntry(addr);
|
||||
if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
|
||||
@ -449,7 +449,7 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t* const data,
|
||||
}
|
||||
}
|
||||
|
||||
bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* const data) {
|
||||
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem(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();
|
||||
@ -497,7 +497,7 @@ 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) {
|
||||
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) {
|
||||
tlm::tlm_generic_payload gp;
|
||||
gp.set_command(tlm::TLM_READ_COMMAND);
|
||||
gp.set_address(addr);
|
||||
@ -507,7 +507,7 @@ bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const d
|
||||
return dbus->transport_dbg(gp) == length;
|
||||
}
|
||||
|
||||
bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) {
|
||||
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) {
|
||||
write_buf.resize(length);
|
||||
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
|
||||
tlm::tlm_generic_payload gp;
|
||||
@ -518,5 +518,10 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t*
|
||||
gp.set_streaming_width(length);
|
||||
return dbus->transport_dbg(gp) == length;
|
||||
}
|
||||
|
||||
template class core_complex<scc::LT>;
|
||||
template class core_complex<32>;
|
||||
template class core_complex<64>;
|
||||
|
||||
} /* namespace tgfs */
|
||||
} /* namespace sysc */
|
||||
|
@ -33,6 +33,7 @@
|
||||
#ifndef _SYSC_CORE_COMPLEX_H_
|
||||
#define _SYSC_CORE_COMPLEX_H_
|
||||
|
||||
#include <scc/signal_opt_ports.h>
|
||||
#include <scc/tick2time.h>
|
||||
#include <scc/traceable.h>
|
||||
#include <scc/utilities.h>
|
||||
@ -40,10 +41,8 @@
|
||||
#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
|
||||
#ifdef CWR_SYSTEMC
|
||||
#include <scmlinc/scml_property.h>
|
||||
#define SOCKET_WIDTH 32
|
||||
#else
|
||||
#include <cci_configuration>
|
||||
#define SOCKET_WIDTH scc::LT
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <tlm>
|
||||
@ -68,12 +67,35 @@ public:
|
||||
namespace tgfs {
|
||||
class core_wrapper;
|
||||
struct core_trace;
|
||||
struct core_complex_if {
|
||||
|
||||
class core_complex : public sc_core::sc_module, public scc::traceable {
|
||||
virtual ~core_complex_if() = default;
|
||||
|
||||
virtual bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) = 0;
|
||||
|
||||
virtual bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) = 0;
|
||||
|
||||
virtual bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) = 0;
|
||||
|
||||
virtual bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) = 0;
|
||||
|
||||
virtual bool disass_output(uint64_t pc, const std::string instr) = 0;
|
||||
|
||||
virtual unsigned get_last_bus_cycles() = 0;
|
||||
|
||||
//! Allow quantum keeper handling
|
||||
virtual void sync(uint64_t) = 0;
|
||||
|
||||
virtual char const* hier_name() = 0;
|
||||
|
||||
scc::sc_in_opt<uint64_t> mtime_i{"mtime_i"};
|
||||
};
|
||||
|
||||
template <unsigned int BUSWIDTH = scc::LT> class core_complex : public sc_core::sc_module, public scc::traceable, public core_complex_if {
|
||||
public:
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> ibus{"ibus"};
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<BUSWIDTH>> ibus{"ibus"};
|
||||
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> dbus{"dbus"};
|
||||
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<BUSWIDTH>> dbus{"dbus"};
|
||||
|
||||
sc_core::sc_in<bool> rst_i{"rst_i"};
|
||||
|
||||
@ -88,8 +110,6 @@ public:
|
||||
#ifndef CWR_SYSTEMC
|
||||
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
||||
|
||||
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o{"mtime_o"};
|
||||
|
||||
cci::cci_param<std::string> elf_file{"elf_file", ""};
|
||||
|
||||
cci::cci_param<bool> enable_disass{"enable_disass", false};
|
||||
@ -115,8 +135,6 @@ public:
|
||||
#else
|
||||
sc_core::sc_in<bool> clk_i{"clk_i"};
|
||||
|
||||
sc_core::sc_in<uint64_t> mtime_i{"mtime_i"};
|
||||
|
||||
scml_property<std::string> elf_file{"elf_file", ""};
|
||||
|
||||
scml_property<bool> enable_disass{"enable_disass", false};
|
||||
@ -159,13 +177,13 @@ public:
|
||||
|
||||
~core_complex();
|
||||
|
||||
inline unsigned get_last_bus_cycles() {
|
||||
unsigned get_last_bus_cycles() override {
|
||||
auto mem_incr = std::max(ibus_inc, dbus_inc);
|
||||
ibus_inc = dbus_inc = 0;
|
||||
return mem_incr > 1 ? mem_incr : 1;
|
||||
}
|
||||
|
||||
inline void sync(uint64_t cycle) {
|
||||
void sync(uint64_t cycle) override {
|
||||
auto core_inc = curr_clk * (cycle - last_sync_cycle);
|
||||
quantum_keeper.inc(core_inc);
|
||||
if(quantum_keeper.need_sync()) {
|
||||
@ -175,20 +193,22 @@ public:
|
||||
last_sync_cycle = cycle;
|
||||
}
|
||||
|
||||
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) override;
|
||||
|
||||
bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data);
|
||||
bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) override;
|
||||
|
||||
bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data);
|
||||
bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) override;
|
||||
|
||||
bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data);
|
||||
bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) override;
|
||||
|
||||
void trace(sc_core::sc_trace_file* trf) const override;
|
||||
|
||||
bool disass_output(uint64_t pc, const std::string instr);
|
||||
bool disass_output(uint64_t pc, const std::string instr) override;
|
||||
|
||||
void set_clock_period(sc_core::sc_time period);
|
||||
|
||||
char const* hier_name() override { return name(); }
|
||||
|
||||
protected:
|
||||
void before_end_of_elaboration() override;
|
||||
void start_of_simulation() override;
|
||||
|
@ -46,12 +46,12 @@ using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc5c|m_p|interp",
|
||||
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
})};
|
||||
@ -62,12 +62,12 @@ using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc5c|m_p|llvm",
|
||||
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc5c|mu_p|llvm", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
})};
|
||||
@ -79,12 +79,12 @@ using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc5c|m_p|tcc",
|
||||
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
})};
|
||||
@ -96,12 +96,12 @@ using namespace sysc;
|
||||
volatile std::array<bool, 2> tgc_init = {
|
||||
iss_factory::instance().register_creator("tgc5c|m_p|asmjit",
|
||||
[](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
}),
|
||||
iss_factory::instance().register_creator("tgc5c|mu_p|asmjit", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
|
||||
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data);
|
||||
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc);
|
||||
return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
|
||||
})};
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t;
|
||||
using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
|
||||
using heart_state_t = typename PLAT::hart_state_type;
|
||||
sc_core_adapter(sysc::tgfs::core_complex* owner)
|
||||
sc_core_adapter(sysc::tgfs::core_complex_if* owner)
|
||||
: owner(owner) {}
|
||||
|
||||
iss::arch_if* get_arch_if() override { return this; }
|
||||
@ -54,9 +54,9 @@ public:
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2)
|
||||
<< (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount + this->cycle_offset << "]";
|
||||
SCCDEBUG(owner->name()) << "disass: "
|
||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||
<< std::setfill(' ') << std::left << instr << s.str();
|
||||
SCCDEBUG(owner->hier_name()) << "disass: "
|
||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t"
|
||||
<< std::setw(40) << std::setfill(' ') << std::left << instr << s.str();
|
||||
}
|
||||
};
|
||||
|
||||
@ -79,10 +79,10 @@ public:
|
||||
switch(hostvar >> 48) {
|
||||
case 0:
|
||||
if(hostvar != 0x1) {
|
||||
SCCINFO(owner->name())
|
||||
SCCINFO(owner->hier_name())
|
||||
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
|
||||
} else {
|
||||
SCCINFO(owner->name())
|
||||
SCCINFO(owner->hier_name())
|
||||
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
@ -112,21 +112,8 @@ public:
|
||||
}
|
||||
|
||||
iss::status read_csr(unsigned addr, reg_t& val) override {
|
||||
#ifndef CWR_SYSTEMC
|
||||
if((addr == iss::arch::time || addr == iss::arch::timeh) && owner->mtime_o.get_interface(0)) {
|
||||
uint64_t time_val;
|
||||
bool ret = owner->mtime_o->nb_peek(time_val);
|
||||
if(addr == iss::arch::time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if(addr == iss::arch::timeh) {
|
||||
if(sizeof(reg_t) != 4)
|
||||
return iss::Err;
|
||||
val = static_cast<reg_t>(time_val >> 32);
|
||||
}
|
||||
return ret ? iss::Ok : iss::Err;
|
||||
#else
|
||||
if((addr == iss::arch::time || addr == iss::arch::timeh)) {
|
||||
uint64_t time_val = owner->mtime_i.read();
|
||||
uint64_t time_val = owner->mtime_i.get_interface() ? owner->mtime_i.read() : 0;
|
||||
if(addr == iss::arch::time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if(addr == iss::arch::timeh) {
|
||||
@ -135,14 +122,13 @@ public:
|
||||
val = static_cast<reg_t>(time_val >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
#endif
|
||||
} else {
|
||||
return PLAT::read_csr(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_until(uint64_t flags) override {
|
||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||
SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt";
|
||||
while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) {
|
||||
sc_core::wait(wfi_evt);
|
||||
}
|
||||
@ -173,11 +159,11 @@ public:
|
||||
this->csr[iss::arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
sysc::tgfs::core_complex* const owner;
|
||||
sysc::tgfs::core_complex_if* const owner{nullptr};
|
||||
sc_core::sc_event wfi_evt;
|
||||
uint64_t hostvar{std::numeric_limits<uint64_t>::max()};
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
|
@ -1,537 +0,0 @@
|
||||
|
||||
|
||||
x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx) {
|
||||
|
||||
x86::Gp tmp_ptr = jh.cc.newUIntPtr("tmp_ptr");
|
||||
jh.cc.mov(tmp_ptr, jh.regs_base_ptr);
|
||||
jh.cc.add(tmp_ptr, traits::reg_byte_offsets[idx]);
|
||||
switch(traits::reg_bit_widths[idx]) {
|
||||
case 8:
|
||||
return x86::ptr_8(tmp_ptr);
|
||||
case 16:
|
||||
return x86::ptr_16(tmp_ptr);
|
||||
case 32:
|
||||
return x86::ptr_32(tmp_ptr);
|
||||
case 64:
|
||||
return x86::ptr_64(tmp_ptr);
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
x86::Gp get_reg_for(jit_holder& jh, unsigned idx) {
|
||||
// TODO can check for regs in jh and return them instead of creating new ones
|
||||
switch(traits::reg_bit_widths[idx]) {
|
||||
case 8:
|
||||
return jh.cc.newInt8();
|
||||
case 16:
|
||||
return jh.cc.newInt16();
|
||||
case 32:
|
||||
return jh.cc.newInt32();
|
||||
case 64:
|
||||
return jh.cc.newInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
x86::Gp get_reg_for(jit_holder& jh, unsigned size, bool is_signed) {
|
||||
if(is_signed)
|
||||
switch(size) {
|
||||
case 8:
|
||||
return jh.cc.newInt8();
|
||||
case 16:
|
||||
return jh.cc.newInt16();
|
||||
case 32:
|
||||
return jh.cc.newInt32();
|
||||
case 64:
|
||||
return jh.cc.newInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
else
|
||||
switch(size) {
|
||||
case 8:
|
||||
return jh.cc.newUInt8();
|
||||
case 16:
|
||||
return jh.cc.newUInt16();
|
||||
case 32:
|
||||
return jh.cc.newUInt32();
|
||||
case 64:
|
||||
return jh.cc.newUInt64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid reg size in get_reg_ptr");
|
||||
}
|
||||
}
|
||||
inline x86::Gp load_reg_from_mem(jit_holder& jh, unsigned idx) {
|
||||
auto ptr = get_reg_ptr(jh, idx);
|
||||
auto reg = get_reg_for(jh, idx);
|
||||
jh.cc.mov(reg, ptr);
|
||||
return reg;
|
||||
}
|
||||
inline void write_reg_to_mem(jit_holder& jh, x86::Gp reg, unsigned idx) {
|
||||
auto ptr = get_reg_ptr(jh, idx);
|
||||
jh.cc.mov(ptr, reg);
|
||||
}
|
||||
|
||||
void gen_instr_prologue(jit_holder& jh, addr_t pc) {
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("\n//(*icount)++;");
|
||||
cc.inc(get_reg_ptr(jh, traits::ICOUNT));
|
||||
|
||||
cc.comment("\n//*pc=*next_pc;");
|
||||
cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc);
|
||||
|
||||
cc.comment("\n//*trap_state=*pending_trap;");
|
||||
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
|
||||
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
|
||||
cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), current_trap_state);
|
||||
|
||||
cc.comment("\n//increment *next_pc");
|
||||
cc.mov(jh.next_pc, pc);
|
||||
}
|
||||
void gen_instr_epilogue(jit_holder& jh) {
|
||||
auto& cc = jh.cc;
|
||||
|
||||
cc.comment("\n//if(*trap_state!=0) goto trap_entry;");
|
||||
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
|
||||
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
|
||||
cc.cmp(current_trap_state, 0);
|
||||
cc.jne(jh.trap_entry);
|
||||
|
||||
// TODO: Does not need to be done for every instruction, only when needed
|
||||
cc.comment("\n//write back regs to mem");
|
||||
write_reg_to_mem(jh, jh.pc, traits::PC);
|
||||
write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC);
|
||||
}
|
||||
void gen_block_prologue(jit_holder& jh) override {
|
||||
|
||||
jh.pc = load_reg_from_mem(jh, traits::PC);
|
||||
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
|
||||
}
|
||||
void gen_block_epilogue(jit_holder& jh) override {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
cc.comment("\n//return *next_pc;");
|
||||
cc.ret(jh.next_pc);
|
||||
|
||||
cc.bind(jh.trap_entry);
|
||||
cc.comment("\n//Prepare for enter_trap;");
|
||||
// Make sure cached values are written back
|
||||
cc.comment("\n//write back regs to mem");
|
||||
write_reg_to_mem(jh, jh.pc, traits::PC);
|
||||
write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC);
|
||||
this->gen_sync(jh, POST_SYNC, -1);
|
||||
|
||||
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
|
||||
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
|
||||
|
||||
x86::Gp current_pc = get_reg_for(jh, traits::PC);
|
||||
cc.mov(current_pc, get_reg_ptr(jh, traits::PC));
|
||||
|
||||
x86::Gp instr = cc.newInt32("instr");
|
||||
cc.mov(instr, 0); // this is not correct
|
||||
cc.comment("\n//enter trap call;");
|
||||
InvokeNode* call_enter_trap;
|
||||
cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT<uint64_t, void*, uint64_t, uint64_t, uint64_t>());
|
||||
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
||||
call_enter_trap->setArg(1, current_trap_state);
|
||||
call_enter_trap->setArg(2, current_pc);
|
||||
call_enter_trap->setArg(3, instr);
|
||||
|
||||
x86::Gp current_next_pc = get_reg_for(jh, traits::NEXT_PC);
|
||||
cc.mov(current_next_pc, get_reg_ptr(jh, traits::NEXT_PC));
|
||||
cc.mov(jh.next_pc, current_next_pc);
|
||||
|
||||
cc.comment("\n//*last_branch = std::numeric_limits<uint32_t>::max();");
|
||||
cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
|
||||
cc.comment("\n//return *next_pc;");
|
||||
cc.ret(jh.next_pc);
|
||||
}
|
||||
/*
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->core.reg.trap_state = trap_val;
|
||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
*/
|
||||
inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) {
|
||||
auto& cc = jh.cc;
|
||||
cc.comment("//gen_raise");
|
||||
auto tmp1 = get_reg_for(jh, traits::TRAP_STATE);
|
||||
cc.mov(tmp1, 0x80ULL << 24 | (cause << 16) | trap_id);
|
||||
cc.mov(get_reg_ptr(jh, traits::TRAP_STATE), tmp1);
|
||||
auto tmp2 = get_reg_for(jh, traits::NEXT_PC);
|
||||
cc.mov(tmp2, std::numeric_limits<uint32_t>::max());
|
||||
cc.mov(get_reg_ptr(jh, traits::NEXT_PC), tmp2);
|
||||
}
|
||||
inline void gen_wait(jit_holder& jh, unsigned type) { jh.cc.comment("//gen_wait"); }
|
||||
inline void gen_leave(jit_holder& jh, unsigned lvl) { jh.cc.comment("//gen_leave"); }
|
||||
|
||||
enum operation { add, sub, band, bor, bxor, shl, sar, shr };
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, operation op, x86::Gp a, T b) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch(op) {
|
||||
case add: {
|
||||
cc.add(a, b);
|
||||
break;
|
||||
}
|
||||
case sub: {
|
||||
cc.sub(a, b);
|
||||
break;
|
||||
}
|
||||
case band: {
|
||||
cc.and_(a, b);
|
||||
break;
|
||||
}
|
||||
case bor: {
|
||||
cc.or_(a, b);
|
||||
break;
|
||||
}
|
||||
case bxor: {
|
||||
cc.xor_(a, b);
|
||||
break;
|
||||
}
|
||||
case shl: {
|
||||
cc.shl(a, b);
|
||||
break;
|
||||
}
|
||||
case sar: {
|
||||
cc.sar(a, b);
|
||||
break;
|
||||
}
|
||||
case shr: {
|
||||
cc.shr(a, b);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (operation)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
enum three_operand_operation { imul, mul, idiv, div, srem, urem };
|
||||
|
||||
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, x86::Gp b) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch(op) {
|
||||
case imul: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.imul(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case mul: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mul(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case idiv: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mov(dummy, 0);
|
||||
cc.idiv(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case div: {
|
||||
x86::Gp dummy = cc.newInt64();
|
||||
cc.mov(dummy, 0);
|
||||
cc.div(dummy, a.r64(), b.r64());
|
||||
return a;
|
||||
}
|
||||
case srem: {
|
||||
x86::Gp rem = cc.newInt32();
|
||||
cc.mov(rem, 0);
|
||||
auto a_reg = cc.newInt32();
|
||||
cc.mov(a_reg, a.r32());
|
||||
cc.idiv(rem, a_reg, b.r32());
|
||||
return rem;
|
||||
}
|
||||
case urem: {
|
||||
x86::Gp rem = cc.newInt32();
|
||||
cc.mov(rem, 0);
|
||||
auto a_reg = cc.newInt32();
|
||||
cc.mov(a_reg, a.r32());
|
||||
cc.div(rem, a_reg, b.r32());
|
||||
return rem;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (three_operand)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, T b) {
|
||||
x86::Gp b_reg = jh.cc.newInt32();
|
||||
/* switch(a.size()){
|
||||
case 1: b_reg = jh.cc.newInt8(); break;
|
||||
case 2: b_reg = jh.cc.newInt16(); break;
|
||||
case 4: b_reg = jh.cc.newInt32(); break;
|
||||
case 8: b_reg = jh.cc.newInt64(); break;
|
||||
default: throw std::runtime_error(fmt::format("Invalid size ({}) in gen operation", a.size()));
|
||||
} */
|
||||
jh.cc.mov(b_reg, b);
|
||||
return gen_operation(jh, op, a, b_reg);
|
||||
}
|
||||
enum comparison_operation { land, lor, eq, ne, lt, ltu, gt, gtu, lte, lteu, gte, gteu };
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
|
||||
x86::Gp gen_operation(jit_holder& jh, comparison_operation op, x86::Gp a, T b) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
x86::Gp tmp = cc.newInt8();
|
||||
cc.mov(tmp, 1);
|
||||
Label label_then = cc.newLabel();
|
||||
cc.cmp(a, b);
|
||||
switch(op) {
|
||||
case eq:
|
||||
cc.je(label_then);
|
||||
break;
|
||||
case ne:
|
||||
cc.jne(label_then);
|
||||
break;
|
||||
case lt:
|
||||
cc.jl(label_then);
|
||||
break;
|
||||
case ltu:
|
||||
cc.jb(label_then);
|
||||
break;
|
||||
case gt:
|
||||
cc.jg(label_then);
|
||||
break;
|
||||
case gtu:
|
||||
cc.ja(label_then);
|
||||
break;
|
||||
case lte:
|
||||
cc.jle(label_then);
|
||||
break;
|
||||
case lteu:
|
||||
cc.jbe(label_then);
|
||||
break;
|
||||
case gte:
|
||||
cc.jge(label_then);
|
||||
break;
|
||||
case gteu:
|
||||
cc.jae(label_then);
|
||||
break;
|
||||
case land: {
|
||||
Label label_false = cc.newLabel();
|
||||
cc.cmp(a, 0);
|
||||
cc.je(label_false);
|
||||
auto b_reg = cc.newInt8();
|
||||
cc.mov(b_reg, b);
|
||||
cc.cmp(b_reg, 0);
|
||||
cc.je(label_false);
|
||||
cc.jmp(label_then);
|
||||
cc.bind(label_false);
|
||||
break;
|
||||
}
|
||||
case lor: {
|
||||
cc.cmp(a, 0);
|
||||
cc.jne(label_then);
|
||||
auto b_reg = cc.newInt8();
|
||||
cc.mov(b_reg, b);
|
||||
cc.cmp(b_reg, 0);
|
||||
cc.jne(label_then);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (comparison)", op));
|
||||
}
|
||||
cc.mov(tmp, 0);
|
||||
cc.bind(label_then);
|
||||
return tmp;
|
||||
}
|
||||
enum binary_operation { lnot, inc, dec, bnot, neg };
|
||||
|
||||
x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
switch(op) {
|
||||
case lnot:
|
||||
throw std::runtime_error("Current operation not supported in gen_operation(lnot)");
|
||||
case inc: {
|
||||
cc.inc(a);
|
||||
break;
|
||||
}
|
||||
case dec: {
|
||||
cc.dec(a);
|
||||
break;
|
||||
}
|
||||
case bnot: {
|
||||
cc.not_(a);
|
||||
break;
|
||||
}
|
||||
case neg: {
|
||||
cc.neg(a);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (unary)", op));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||
inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) {
|
||||
auto val_reg = get_reg_for(jh, sizeof(val) * 8, is_signed);
|
||||
jh.cc.mov(val_reg, val);
|
||||
return gen_ext(jh, val_reg, size, is_signed);
|
||||
}
|
||||
inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) {
|
||||
auto& cc = jh.cc;
|
||||
if(is_signed) {
|
||||
switch(val.size()) {
|
||||
case 1:
|
||||
cc.cbw(val);
|
||||
break;
|
||||
case 2:
|
||||
cc.cwde(val);
|
||||
break;
|
||||
case 4:
|
||||
cc.cdqe(val);
|
||||
break;
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid register size in gen_ext");
|
||||
}
|
||||
}
|
||||
switch(size) {
|
||||
case 8:
|
||||
cc.and_(val, std::numeric_limits<uint8_t>::max());
|
||||
return val.r8();
|
||||
case 16:
|
||||
cc.and_(val, std::numeric_limits<uint16_t>::max());
|
||||
return val.r16();
|
||||
case 32:
|
||||
cc.and_(val, std::numeric_limits<uint32_t>::max());
|
||||
return val.r32();
|
||||
case 64:
|
||||
cc.and_(val, std::numeric_limits<uint64_t>::max());
|
||||
return val.r64();
|
||||
case 128:
|
||||
return val.r64();
|
||||
default:
|
||||
throw std::runtime_error("Invalid size in gen_ext");
|
||||
}
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
auto ret_reg = cc.newInt32();
|
||||
|
||||
auto mem_type_reg = cc.newInt32();
|
||||
cc.mov(mem_type_reg, type);
|
||||
|
||||
auto space_reg = cc.newInt32();
|
||||
cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
|
||||
|
||||
auto val_ptr = cc.newUIntPtr();
|
||||
cc.mov(val_ptr, read_mem_buf);
|
||||
|
||||
InvokeNode* invokeNode;
|
||||
uint64_t mask = 0;
|
||||
x86::Gp val_reg = cc.newInt64();
|
||||
|
||||
switch(length) {
|
||||
case 1: {
|
||||
cc.invoke(&invokeNode, &read_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint8_t>::max();
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
cc.invoke(&invokeNode, &read_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint16_t>::max();
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
cc.invoke(&invokeNode, &read_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint32_t>::max();
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
cc.invoke(&invokeNode, &read_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
|
||||
mask = std::numeric_limits<uint64_t>::max();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Invalid length ({}) in gen_read_mem", length));
|
||||
}
|
||||
|
||||
invokeNode->setRet(0, ret_reg);
|
||||
invokeNode->setArg(0, jh.arch_if_ptr);
|
||||
invokeNode->setArg(1, space_reg);
|
||||
invokeNode->setArg(2, mem_type_reg);
|
||||
invokeNode->setArg(3, addr);
|
||||
invokeNode->setArg(4, val_ptr);
|
||||
cc.cmp(ret_reg, 0);
|
||||
cc.jne(jh.trap_entry);
|
||||
|
||||
cc.mov(val_reg, x86::ptr_64(val_ptr));
|
||||
cc.and_(val_reg, mask);
|
||||
return val_reg;
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length) {
|
||||
throw std::runtime_error("Invalid gen_read_mem");
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length) {
|
||||
throw std::runtime_error("Invalid gen_read_mem");
|
||||
}
|
||||
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length) {
|
||||
auto addr_reg = jh.cc.newInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
|
||||
return gen_read_mem(jh, type, addr_reg, length);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val, uint32_t length) {
|
||||
auto val_reg = get_reg_for(jh, length * 8, true);
|
||||
jh.cc.mov(val_reg, val);
|
||||
gen_write_mem(jh, type, addr, val_reg, length);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val, uint32_t length) {
|
||||
x86::Compiler& cc = jh.cc;
|
||||
assert(val.size() == length);
|
||||
auto mem_type_reg = cc.newInt32();
|
||||
jh.cc.mov(mem_type_reg, type);
|
||||
auto space_reg = cc.newInt32();
|
||||
jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
|
||||
auto ret_reg = cc.newInt32();
|
||||
InvokeNode* invokeNode;
|
||||
switch(length) {
|
||||
case 1:
|
||||
cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>());
|
||||
|
||||
break;
|
||||
case 2:
|
||||
cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>());
|
||||
break;
|
||||
case 4:
|
||||
cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>());
|
||||
break;
|
||||
case 8:
|
||||
cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>());
|
||||
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid register size in gen_ext");
|
||||
}
|
||||
invokeNode->setRet(0, ret_reg);
|
||||
invokeNode->setArg(0, jh.arch_if_ptr);
|
||||
invokeNode->setArg(1, space_reg);
|
||||
invokeNode->setArg(2, mem_type_reg);
|
||||
invokeNode->setArg(3, addr);
|
||||
invokeNode->setArg(4, val);
|
||||
|
||||
cc.cmp(ret_reg, 0);
|
||||
cc.jne(jh.trap_entry);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val, uint32_t length) {
|
||||
auto addr_reg = jh.cc.newUInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
gen_write_mem(jh, type, addr_reg, val, length);
|
||||
}
|
||||
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val, uint32_t length) {
|
||||
auto val_reg = get_reg_for(jh, length * 8, true);
|
||||
jh.cc.mov(val_reg, val);
|
||||
|
||||
auto addr_reg = jh.cc.newUInt64();
|
||||
jh.cc.mov(addr_reg, addr);
|
||||
gen_write_mem(jh, type, addr_reg, val_reg, length);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fp_functions.h"
|
||||
#include <array>
|
||||
|
||||
extern "C" {
|
||||
#include "internals.h"
|
||||
@ -43,9 +44,10 @@ extern "C" {
|
||||
#include <limits>
|
||||
|
||||
using this_t = uint8_t*;
|
||||
const uint8_t rmm_map[] = {
|
||||
// this does not inlcude any reserved rm or the DYN rm, as DYN rm should be taken care of in the vm_impl
|
||||
const std::array<uint8_t, 5> rmm_map = {
|
||||
softfloat_round_near_even /*RNE*/, softfloat_round_minMag /*RTZ*/, softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/,
|
||||
softfloat_round_near_maxMag /*RMM*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/,
|
||||
softfloat_round_near_maxMag /*RMM*/
|
||||
};
|
||||
|
||||
const uint32_t quiet_nan32 = 0x7fC00000;
|
||||
@ -56,7 +58,7 @@ uint32_t fget_flags() { return softfloat_exceptionFlags & 0x1f; }
|
||||
|
||||
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
float32_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r = f32_add(v1f, v2f);
|
||||
return r.v;
|
||||
@ -64,7 +66,7 @@ uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
|
||||
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
float32_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r = f32_sub(v1f, v2f);
|
||||
return r.v;
|
||||
@ -72,7 +74,7 @@ uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
|
||||
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
float32_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r = f32_mul(v1f, v2f);
|
||||
return r.v;
|
||||
@ -80,7 +82,7 @@ uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
|
||||
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
float32_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r = f32_div(v1f, v2f);
|
||||
return r.v;
|
||||
@ -88,7 +90,7 @@ uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
|
||||
|
||||
uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
|
||||
float32_t v1f{v1};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r = f32_sqrt(v1f);
|
||||
return r.v;
|
||||
@ -130,18 +132,18 @@ uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t r;
|
||||
switch(op) {
|
||||
case 0: { // w->s, fp to int32
|
||||
uint_fast32_t res = f32_to_i32(v1f, rmm_map[mode & 0x7], true);
|
||||
case 0: { // FCVT__W__S
|
||||
uint_fast32_t res = f32_to_i32(v1f, rmm_map.at(mode), true);
|
||||
return (uint32_t)res;
|
||||
}
|
||||
case 1: { // wu->s
|
||||
uint_fast32_t res = f32_to_ui32(v1f, rmm_map[mode & 0x7], true);
|
||||
case 1: { // FCVT__WU__S
|
||||
uint_fast32_t res = f32_to_ui32(v1f, rmm_map.at(mode), true);
|
||||
return (uint32_t)res;
|
||||
}
|
||||
case 2: // s->w
|
||||
r = i32_to_f32(v1);
|
||||
case 2: // FCVT__S__W
|
||||
r = i32_to_f32((int32_t)v1);
|
||||
return r.v;
|
||||
case 3: // s->wu
|
||||
case 3: // FCVT__S__WU
|
||||
r = ui32_to_f32(v1);
|
||||
return r.v;
|
||||
}
|
||||
@ -149,12 +151,24 @@ uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
|
||||
}
|
||||
|
||||
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode) {
|
||||
// op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
uint32_t F32_SIGN = 1UL << 31;
|
||||
switch(op) {
|
||||
case 0: // FMADD_S
|
||||
break;
|
||||
case 1: // FMSUB_S
|
||||
v3 ^= F32_SIGN;
|
||||
break;
|
||||
case 2: // FNMADD_S
|
||||
v1 ^= F32_SIGN;
|
||||
v3 ^= F32_SIGN;
|
||||
break;
|
||||
case 3: // FNMSUB_S
|
||||
v1 ^= F32_SIGN;
|
||||
break;
|
||||
}
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float32_t res = softfloat_mulAddF32(v1, v2, v3, op & 0x1);
|
||||
if(op > 1)
|
||||
res.v ^= 1ULL << 31;
|
||||
float32_t res = softfloat_mulAddF32(v1, v2, v3, 0);
|
||||
return res.v;
|
||||
}
|
||||
|
||||
@ -189,8 +203,8 @@ uint32_t fclass_s(uint32_t v1) {
|
||||
uA.f = a;
|
||||
uiA = uA.ui;
|
||||
|
||||
uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF;
|
||||
uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0;
|
||||
bool infOrNaN = expF32UI(uiA) == 0xFF;
|
||||
bool subnormalOrZero = expF32UI(uiA) == 0;
|
||||
bool sign = signF32UI(uiA);
|
||||
bool fracZero = fracF32UI(uiA) == 0;
|
||||
bool isNaN = isNaNF32UI(uiA);
|
||||
@ -203,9 +217,13 @@ uint32_t fclass_s(uint32_t v1) {
|
||||
}
|
||||
|
||||
uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
bool nan = (v1 & defaultNaNF64UI) == defaultNaNF64UI;
|
||||
if(nan) {
|
||||
bool isNan = isNaNF64UI(v1);
|
||||
bool isSNaN = softfloat_isSigNaNF64UI(v1);
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
if(isNan) {
|
||||
if(isSNaN)
|
||||
softfloat_raiseFlags(softfloat_flag_invalid);
|
||||
return defaultNaNF32UI;
|
||||
} else {
|
||||
float32_t res = f64_to_f32(float64_t{v1});
|
||||
@ -214,11 +232,11 @@ uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
|
||||
}
|
||||
|
||||
uint64_t fconv_f2d(uint32_t v1, uint8_t mode) {
|
||||
bool nan = (v1 & defaultNaNF32UI) == defaultNaNF32UI;
|
||||
if(nan) {
|
||||
bool infOrNaN = expF32UI(v1) == 0xFF;
|
||||
bool subnormalOrZero = expF32UI(v1) == 0;
|
||||
if(infOrNaN || subnormalOrZero) {
|
||||
return defaultNaNF64UI;
|
||||
} else {
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
float64_t res = f32_to_f64(float32_t{v1});
|
||||
return res.v;
|
||||
}
|
||||
@ -228,7 +246,7 @@ uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32;
|
||||
bool snan = softfloat_isSigNaNF32UI(v1);
|
||||
float64_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r = f64_add(v1f, v2f);
|
||||
return r.v;
|
||||
@ -236,7 +254,7 @@ uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
|
||||
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
float64_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r = f64_sub(v1f, v2f);
|
||||
return r.v;
|
||||
@ -244,7 +262,7 @@ uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
|
||||
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
float64_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r = f64_mul(v1f, v2f);
|
||||
return r.v;
|
||||
@ -252,7 +270,7 @@ uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
|
||||
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
float64_t v1f{v1}, v2f{v2};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r = f64_div(v1f, v2f);
|
||||
return r.v;
|
||||
@ -260,7 +278,7 @@ uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
|
||||
|
||||
uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
|
||||
float64_t v1f{v1};
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r = f64_sqrt(v1f);
|
||||
return r.v;
|
||||
@ -298,22 +316,23 @@ uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
|
||||
}
|
||||
|
||||
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
|
||||
|
||||
float64_t v1f{v1};
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t r;
|
||||
switch(op) {
|
||||
case 0: { // l->d, fp to int32
|
||||
int64_t res = f64_to_i64(v1f, rmm_map[mode & 0x7], true);
|
||||
case 0: { // l from d
|
||||
int64_t res = f64_to_i64(v1f, rmm_map.at(mode), true);
|
||||
return (uint64_t)res;
|
||||
}
|
||||
case 1: { // lu->s
|
||||
uint64_t res = f64_to_ui64(v1f, rmm_map[mode & 0x7], true);
|
||||
case 1: { // lu from d
|
||||
uint64_t res = f64_to_ui64(v1f, rmm_map.at(mode), true);
|
||||
return res;
|
||||
}
|
||||
case 2: // s->l
|
||||
case 2: // d from l
|
||||
r = i64_to_f64(v1);
|
||||
return r.v;
|
||||
case 3: // s->lu
|
||||
case 3: // d from lu
|
||||
r = ui64_to_f64(v1);
|
||||
return r.v;
|
||||
}
|
||||
@ -321,12 +340,24 @@ uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
|
||||
}
|
||||
|
||||
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode) {
|
||||
// op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
|
||||
softfloat_roundingMode = rmm_map[mode & 0x7];
|
||||
uint64_t F64_SIGN = 1ULL << 63;
|
||||
switch(op) {
|
||||
case 0: // FMADD_D
|
||||
break;
|
||||
case 1: // FMSUB_D
|
||||
v3 ^= F64_SIGN;
|
||||
break;
|
||||
case 2: // FNMADD_D
|
||||
v1 ^= F64_SIGN;
|
||||
v3 ^= F64_SIGN;
|
||||
break;
|
||||
case 3: // FNMSUB_D
|
||||
v1 ^= F64_SIGN;
|
||||
break;
|
||||
}
|
||||
softfloat_roundingMode = rmm_map.at(mode);
|
||||
softfloat_exceptionFlags = 0;
|
||||
float64_t res = softfloat_mulAddF64(v1, v2, v3, op & 0x1);
|
||||
if(op > 1)
|
||||
res.v ^= 1ULL << 63;
|
||||
float64_t res = softfloat_mulAddF64(v1, v2, v3, 0);
|
||||
return res.v;
|
||||
}
|
||||
|
||||
@ -362,8 +393,8 @@ uint64_t fclass_d(uint64_t v1) {
|
||||
uA.f = a;
|
||||
uiA = uA.ui;
|
||||
|
||||
uint_fast16_t infOrNaN = expF64UI(uiA) == 0x7FF;
|
||||
uint_fast16_t subnormalOrZero = expF64UI(uiA) == 0;
|
||||
bool infOrNaN = expF64UI(uiA) == 0x7FF;
|
||||
bool subnormalOrZero = expF64UI(uiA) == 0;
|
||||
bool sign = signF64UI(uiA);
|
||||
bool fracZero = fracF64UI(uiA) == 0;
|
||||
bool isNaN = isNaNF64UI(uiA);
|
||||
@ -381,9 +412,9 @@ uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode) {
|
||||
float64_t r;
|
||||
switch(op) {
|
||||
case 0: // l->s, fp to int32
|
||||
return f32_to_i64(v1f, rmm_map[mode & 0x7], true);
|
||||
return f32_to_i64(v1f, rmm_map.at(mode), true);
|
||||
case 1: // wu->s
|
||||
return f32_to_ui64(v1f, rmm_map[mode & 0x7], true);
|
||||
return f32_to_ui64(v1f, rmm_map.at(mode), true);
|
||||
case 2: // s->w
|
||||
r = i32_to_f64(v1);
|
||||
return r.v;
|
||||
@ -399,11 +430,11 @@ uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode) {
|
||||
float32_t r;
|
||||
switch(op) {
|
||||
case 0: { // wu->s
|
||||
int32_t r = f64_to_i32(float64_t{v1}, rmm_map[mode & 0x7], true);
|
||||
int32_t r = f64_to_i32(float64_t{v1}, rmm_map.at(mode), true);
|
||||
return r;
|
||||
}
|
||||
case 1: { // wu->s
|
||||
uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map[mode & 0x7], true);
|
||||
uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map.at(mode), true);
|
||||
return r;
|
||||
}
|
||||
case 2: // l->s, fp to int32
|
||||
|
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