5 Commits

525 changed files with 57613 additions and 64927 deletions

View File

@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.12)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
############################################################################### ###############################################################################
# #
############################################################################### ###############################################################################
@ -20,41 +19,33 @@ set(LIB_SOURCES
src/iss/arch/tgc5c.cpp src/iss/arch/tgc5c.cpp
src/vm/interp/vm_tgc5c.cpp src/vm/interp/vm_tgc5c.cpp
src/vm/fp_functions.cpp src/vm/fp_functions.cpp
src/iss/debugger/csr_names.cpp
src/iss/semihosting/semihosting.cpp
) )
if(WITH_TCC) if(WITH_TCC)
list(APPEND LIB_SOURCES list(APPEND LIB_SOURCES
src/vm/tcc/vm_tgc5c.cpp src/vm/tcc/vm_tgc5c.cpp
) )
endif() endif()
if(WITH_LLVM) if(WITH_LLVM)
list(APPEND LIB_SOURCES list(APPEND LIB_SOURCES
src/vm/llvm/vm_tgc5c.cpp src/vm/llvm/vm_tgc5c.cpp
src/vm/llvm/fp_impl.cpp src/vm/llvm/fp_impl.cpp
) )
endif() endif()
if(WITH_ASMJIT) if(WITH_ASMJIT)
list(APPEND LIB_SOURCES list(APPEND LIB_SOURCES
src/vm/asmjit/vm_tgc5c.cpp src/vm/asmjit/vm_tgc5c.cpp
) )
endif() endif()
# library files # library files
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp) 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_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
FILE(GLOB GEN_YAML_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/contrib/instr/*.yaml) FILE(GLOB GEN_YAML_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/contrib/instr/*.yaml)
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES}) list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
foreach(FILEPATH ${GEN_ISS_SOURCES}) foreach(FILEPATH ${GEN_ISS_SOURCES})
get_filename_component(CORE ${FILEPATH} NAME_WE) get_filename_component(CORE ${FILEPATH} NAME_WE)
string(TOUPPER ${CORE} CORE) string(TOUPPER ${CORE} CORE)
list(APPEND LIB_DEFINES CORE_${CORE}) list(APPEND LIB_DEFINES CORE_${CORE})
endforeach() endforeach()
message(STATUS "Core defines are ${LIB_DEFINES}") message(STATUS "Core defines are ${LIB_DEFINES}")
if(WITH_LLVM) if(WITH_LLVM)
@ -66,19 +57,16 @@ if(WITH_TCC)
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp) FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES}) list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif() endif()
if(WITH_ASMJIT) if(WITH_ASMJIT)
FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/asmjit/vm_*.cpp) FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/asmjit/vm_*.cpp)
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES}) list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif() endif()
if(TARGET yaml-cpp::yaml-cpp) if(TARGET yaml-cpp::yaml-cpp)
list(APPEND LIB_SOURCES list(APPEND LIB_SOURCES
src/iss/plugin/cycle_estimate.cpp src/iss/plugin/cycle_estimate.cpp
src/iss/plugin/instruction_count.cpp src/iss/plugin/instruction_count.cpp
) )
endif() endif()
# Define the library # Define the library
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES}) add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
@ -87,36 +75,32 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293) target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif() endif()
target_include_directories(${PROJECT_NAME} PUBLIC src) target_include_directories(${PROJECT_NAME} PUBLIC src)
target_include_directories(${PROJECT_NAME} PUBLIC src-gen) target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core) target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core)
# only re-export the include paths # only re-export the include paths
get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES) get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL}) target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL})
get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS) 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}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
endif() endif()
target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine) target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)
if(TARGET yaml-cpp::yaml-cpp) if(TARGET yaml-cpp::yaml-cpp)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS)
target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp) target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp)
endif() endif()
# if(WITH_LLVM) if(WITH_LLVM)
# target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS}) find_package(LLVM)
# target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${LLVM_DEFINITIONS})
target_include_directories(${PROJECT_NAME} PUBLIC ${LLVM_INCLUDE_DIRS})
# if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)
# target_link_libraries(${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES}) target_link_libraries( ${PROJECT_NAME} PUBLIC ${LLVM_LIBRARIES})
# endif() endif()
# endif() endif()
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
@ -137,7 +121,6 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
PATTERN "*.h" # select header files PATTERN "*.h" # select header files
) )
install(FILES ${GEN_YAML_SOURCES} DESTINATION share/tgc-vp) install(FILES ${GEN_YAML_SOURCES} DESTINATION share/tgc-vp)
############################################################################### ###############################################################################
# #
############################################################################### ###############################################################################
@ -146,7 +129,6 @@ project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED) find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp) add_executable(${PROJECT_NAME} src/main.cpp)
if(TARGET ${CORE_NAME}_cpp) if(TARGET ${CORE_NAME}_cpp)
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES}) list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
else() else()
@ -172,6 +154,7 @@ endforeach()
#if(WITH_TCC) #if(WITH_TCC)
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC) # target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
#endif() #endif()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)
if(TARGET Boost::program_options) if(TARGET Boost::program_options)
@ -179,9 +162,7 @@ if(TARGET Boost::program_options)
else() else()
target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY}) target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY})
endif() endif()
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
if (Tcmalloc_FOUND) if (Tcmalloc_FOUND)
target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES}) target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
endif(Tcmalloc_FOUND) endif(Tcmalloc_FOUND)
@ -200,23 +181,19 @@ if(BUILD_TESTING)
# ... CMake code to create tests ... # ... CMake code to create tests ...
add_test(NAME tgc-sim-interp add_test(NAME tgc-sim-interp
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp) COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp)
if(WITH_TCC) if(WITH_TCC)
add_test(NAME tgc-sim-tcc add_test(NAME tgc-sim-tcc
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc) COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc)
endif() endif()
if(WITH_LLVM) if(WITH_LLVM)
add_test(NAME tgc-sim-llvm add_test(NAME tgc-sim-llvm
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm) COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm)
endif() endif()
if(WITH_ASMJIT) if(WITH_ASMJIT)
add_test(NAME tgc-sim-asmjit add_test(NAME tgc-sim-asmjit
COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend asmjit) COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend asmjit)
endif() endif()
endif() endif()
############################################################################### ###############################################################################
# #
############################################################################### ###############################################################################
@ -231,7 +208,6 @@ if(TARGET scc-sysc)
add_library(${PROJECT_NAME} ${LIB_SOURCES}) add_library(${PROJECT_NAME} ${LIB_SOURCES})
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
foreach(F IN LISTS TGC_SOURCES) foreach(F IN LISTS TGC_SOURCES)
if (${F} MATCHES ".*/arch/([^/]*)\.cpp") if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F}) string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
@ -239,12 +215,11 @@ if(TARGET scc-sysc)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endif() endif()
endforeach() endforeach()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
# if(WITH_LLVM) # if(WITH_LLVM)
# target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) # target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
# endif() # endif()
set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h) set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
@ -262,8 +237,3 @@ if(TARGET scc-sysc)
) )
endif() 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)

View File

@ -349,7 +349,7 @@ Zifencei:
size: 32 size: 32
branch: false branch: false
delay: 1 delay: 1
RVM: RV32M:
MUL: MUL:
index: 49 index: 49
encoding: 0b00000010000000000000000000110011 encoding: 0b00000010000000000000000000110011

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2024 MINRES Technologies GmbH * Copyright (C) 2017 - 2020 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -47,10 +47,10 @@ def getRegisterSizes(){
using namespace iss::arch; 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_names;
constexpr std::array<const char*, ${registers.size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases; 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_bit_widths;
constexpr std::array<const uint32_t, ${getRegisterSizes().size()}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets; constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default; ${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default;

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2024 MINRES Technologies GmbH * Copyright (C) 2017 - 2021 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -75,10 +75,10 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}"; constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${registers.size()}> reg_names{ static constexpr std::array<const char*, ${registers.size}> reg_names{
{"${registers.collect{it.name.toLowerCase()}.join('", "')}"}}; {"${registers.collect{it.name.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('", "')}"}}; {"${registers.collect{it.alias.toLowerCase()}.join('", "')}"}};
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.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>; 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(',')}}}; {${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(',')}}}; {${getRegisterOffsets().join(',')}}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS }; enum sreg_flag_e { FLAGS };
enum mem_type_e { ${spaces.collect{it.name}.join(', ')}, IMEM = MEM }; enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %> enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %>
${instr.instruction.name} = ${index},<%}%> ${instr.instruction.name} = ${index},<%}%>
@ -131,6 +131,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
uint8_t* get_regs_base_ptr() override; uint8_t* get_regs_base_ptr() override;
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; } inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; } inline uint64_t stop_code() { return interrupt_sim; }
@ -139,6 +141,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; }
#pragma pack(push, 1) #pragma pack(push, 1)
struct ${coreDef.name}_regs {<% struct ${coreDef.name}_regs {<%

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2024 MINRES Technologies GmbH * Copyright (C) 2023 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -45,17 +45,17 @@ namespace interp {
using namespace sysc; using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = { 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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") {%>, })<%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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(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); 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)}}; 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; using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = { 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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") {%>, })<%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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(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); 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)}}; 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; using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = { 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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") {%>, })<%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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(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); 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)}}; 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; using namespace sysc;
volatile std::array<bool, ${array_count}> ${coreDef.name.toLowerCase()}_init = { 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc); 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)}}; 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") {%>, })<%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 { 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_if*>(data); auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(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); 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)}}; return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
})<%}%> })<%}%>

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017-2024 MINRES Technologies GmbH * Copyright (C) 2017, 2023 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,10 +37,7 @@
#include <iss/asmjit/vm_base.h> #include <iss/asmjit/vm_base.h>
#include <asmjit/asmjit.h> #include <asmjit/asmjit.h>
#include <util/logging.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 #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -82,33 +79,12 @@ public:
} }
protected: protected:
using super::get_ptr_for; using vm_base<ARCH>::get_reg_ptr;
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 this_class = vm_impl<ARCH>;
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&); 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&, unsigned int &, 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);} 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> template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) { inline S sext(U from) {
@ -116,29 +92,34 @@ protected:
auto sign_mask = 1ULL<<(W-1); auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0); return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} }
<%functions.each{ it.eachLine { %> #include <vm/asmjit/helper_func.h>
${it}<%}%>
<%}%>
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct instruction_descriptor {
uint32_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
compile_func op; compile_func op;
}; };
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{ decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}}; }};
//needs to be declared after instr_descr
decoder instr_decoder;
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */ /* instruction ${idx}: ${instr.name} */
continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
@ -146,82 +127,105 @@ private:
<%instr.fields.eachLine{%>${it} <%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate disass */ /* 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; x86::Compiler& cc = jh.cc;
cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str()); //ideally only do this if necessary (someone / plugin needs it)
gen_sync(jh, PRE_SYNC, ${idx}); cc.mov(jh.pc,PC);
mov(cc, jh.pc, pc.val); cc.comment(fmt::format("\\n${instr.name}_{:#x}:",pc.val).c_str());
gen_set_tval(jh, instr); this->gen_sync(jh, PRE_SYNC, ${idx});
pc=pc+ ${instr.length/8}; pc=pc+ ${instr.length/8};
mov(cc, jh.next_pc, pc.val);
gen_instr_prologue(jh); gen_instr_prologue(jh, pc.val);
cc.comment("//behavior:"); cc.comment("\\n//behavior:");
/*generate behavior*/ /*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
gen_sync(jh, POST_SYNC, ${idx});
gen_instr_epilogue(jh); gen_instr_epilogue(jh);
this->gen_sync(jh, POST_SYNC, ${idx});
return returnValue; return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
continuation_e illegal_instruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) { continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
x86::Compiler& cc = jh.cc;
if(this->disass_enabled){ return BRANCH;
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);
} }
cc.comment(fmt::format("illegal_instruction{:#x}:",pc.val).c_str()); //decoding functionality
gen_sync(jh, PRE_SYNC, instr_descr.size());
mov(cc, jh.pc, pc.val); void populate_decoding_tree(decoding_tree_node* root){
gen_set_tval(jh, instr); //create submask
pc = pc + ((instr & 3) == 3 ? 4 : 2); for(auto instr: root->instrs){
mov(cc, jh.next_pc, pc.val); root->submask &= instr.mask;
gen_instr_prologue(jh); }
cc.comment("//behavior:"); //put each instr according to submask&encoding into children
gen_raise(jh, 0, 2); for(auto instr: root->instrs){
gen_sync(jh, POST_SYNC, instr_descr.size()); bool foundMatch = false;
gen_instr_epilogue(jh); for(auto child: root->children){
return ILLEGAL_INSTR; //use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
compile_func decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return nullptr;
} }
}; };
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
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() { this(new ARCH()); }
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) : vm_base<ARCH>(core, core_id, cluster_id) {
, instr_decoder([this]() { root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
std::vector<generic_instruction_descriptor> g_instr_descr; for(auto instr: instr_descr){
g_instr_descr.reserve(instr_descr.size()); root->instrs.push_back(instr);
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}; populate_decoding_tree(root);
g_instr_descr.push_back(new_instr_descr);
} }
return std::move(g_instr_descr);
}()) {}
template <typename ARCH> 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, unsigned int &inst_cnt, jit_holder& jh) {
enum {TRAP_ID=1<<16}; enum {TRAP_ID=1<<16};
code_word_t instr = 0; code_word_t instr = 0;
phys_addr_t paddr(pc); phys_addr_t paddr(pc);
@ -230,105 +234,19 @@ continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned
paddr = this->core.virt2phys(pc); paddr = this->core.virt2phys(pc);
auto res = this->core.read(paddr, 4, data); auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) if (res != iss::Ok)
return ILLEGAL_FETCH; throw trap_access(TRAP_ID, pc.val);
if (instr == 0x0000006f || (instr&0xffff)==0xa001) if (instr == 0x0000006f || (instr&0xffff)==0xa001)
return JUMP_TO_SELF; throw simulation_stopped(0); // 'J 0' or 'C.J 0'
++inst_cnt; ++inst_cnt;
uint32_t inst_index = instr_decoder.decode_instr(instr); auto f = decode_instr(root, instr);
compile_func f = nullptr;
if(inst_index < instr_descr.size())
f = instr_descr[inst_index].op;
if (f == nullptr) if (f == nullptr)
f = &this_class::illegal_instruction; f = &this_class::illegal_intruction;
return (this->*f)(pc, instr, jh); 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 <> template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
@ -339,30 +257,22 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} // namespace asmjit } // namespace asmjit
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h> #include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h> #include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss { namespace iss {
namespace { namespace {
volatile std::array<bool, 2> dummy = { volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}), }),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>(); 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}) })
}; };

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017-2024 MINRES Technologies GmbH * Copyright (C) 2021 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,7 +35,6 @@ def nativeTypeSize(int size){
} }
%> %>
// clang-format off // clang-format off
#include <cstdint>
#include <iss/arch/${coreDef.name.toLowerCase()}.h> #include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
@ -48,8 +47,6 @@ def nativeTypeSize(int size){
#include <exception> #include <exception>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <iss/instruction_decoder.h>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
@ -100,12 +97,7 @@ protected:
using compile_ret_t = virt_addr_t; using compile_ret_t = virt_addr_t;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr); using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
inline const char *name(size_t index){return traits::reg_aliases.at(index);} inline const char *name(size_t index){return index<traits::reg_aliases.size()?traits::reg_aliases[index]:"illegal";}
<%
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; virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
@ -114,6 +106,7 @@ if(fcsr != null) {%>
inline void raise(uint16_t trap_id, uint16_t cause){ inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.reg.trap_state = trap_val; 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){ inline void leave(unsigned lvl){
@ -124,13 +117,6 @@ if(fcsr != null) {%>
this->core.wait_until(type); 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 yield_t = boost::coroutines2::coroutine<void>::push_type;
using coro_t = boost::coroutines2::coroutine<void>::pull_type; using coro_t = boost::coroutines2::coroutine<void>::pull_type;
std::vector<coro_t> spawn_blocks; std::vector<coro_t> spawn_blocks;
@ -160,20 +146,25 @@ private:
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct instruction_descriptor {
uint32_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
typename arch::traits<ARCH>::opcode_e op; typename arch::traits<ARCH>::opcode_e op;
}; };
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{ decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%> {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
}}; }};
//needs to be declared after instr_descr
decoder instr_decoder;
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
if(this->core.has_mmu()) { if(this->core.has_mmu()) {
auto phys_pc = this->core.virt2phys(pc); auto phys_pc = this->core.virt2phys(pc);
@ -193,6 +184,57 @@ private:
} }
return iss::Ok; return iss::Ok;
} }
void populate_decoding_tree(decoding_tree_node* root){
//create submask
for(auto instr: root->instrs){
root->submask &= instr.mask;
}
//put each instr according to submask&encoding into children
for(auto instr: root->instrs){
bool foundMatch = false;
for(auto child: root->children){
//use value as identifying trait
if(child->value == (instr.value&root->submask)){
child->instrs.push_back(instr);
foundMatch = true;
}
}
if(!foundMatch){
decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
child->instrs.push_back(instr);
root->children.push_back(child);
}
}
root->instrs.clear();
//call populate_decoding_tree for all children
if(root->children.size() >1)
for(auto child: root->children){
populate_decoding_tree(child);
}
else{
//sort instrs by value of the mask, this works bc we want to have the least restrictive one last
std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
return instr1.mask > instr2.mask;
});
}
}
typename arch::traits<ARCH>::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){
if(!node->children.size()){
if(node->instrs.size() == 1) return node->instrs[0].op;
for(auto instr : node->instrs){
if((instr.mask&word) == instr.value) return instr.op;
}
}
else{
for(auto child : node->children){
if (child->value == (node->submask&word)){
return decode_instr(child, word);
}
}
}
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
}
}; };
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
@ -218,23 +260,16 @@ constexpr size_t bit_count(uint32_t u) {
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) : vm_base<ARCH>(core, core_id, cluster_id) {
, instr_decoder([this]() { root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
std::vector<generic_instruction_descriptor> g_instr_descr; for(auto instr:instr_descr){
g_instr_descr.reserve(instr_descr.size()); root->instrs.push_back(instr);
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);
} }
return std::move(g_instr_descr); populate_decoding_tree(root);
}()) {}
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_fcount_limit_enabled(finish_cond_e cond){ inline bool is_count_limit_enabled(finish_cond_e cond){
return (cond & finish_cond_e::FCOUNT_LIMIT) == finish_cond_e::FCOUNT_LIMIT; return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT;
} }
inline bool is_jump_to_self_enabled(finish_cond_e cond){ inline bool is_jump_to_self_enabled(finish_cond_e cond){
@ -242,7 +277,7 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
} }
template <typename ARCH> template <typename ARCH>
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t count_limit){ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
auto pc=start; auto pc=start;
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
@ -255,24 +290,14 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
auto *const data = reinterpret_cast<uint8_t*>(&instr); auto *const data = reinterpret_cast<uint8_t*>(&instr);
while(!this->core.should_stop() && while(!this->core.should_stop() &&
!(is_icount_limit_enabled(cond) && icount >= count_limit) && !(is_count_limit_enabled(cond) && icount >= icount_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){ if(fetch_ins(pc, data)!=iss::Ok){
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max()); this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
process_spawn_blocks(); pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
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 { } else {
if (is_jump_to_self_enabled(cond) && if (is_jump_to_self_enabled(cond) &&
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
uint32_t inst_index = instr_decoder.decode_instr(instr); auto inst_id = decode_instr(root, 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 // pre execution stuff
this->core.reg.last_branch = 0; this->core.reg.last_branch = 0;
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
@ -283,7 +308,6 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%> /* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%> ${it}<%}%>
this->core.disass_output(pc.val, mnemonic);
} }
// used registers<%instr.usedVariables.each{ k,v-> // used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%> if(v.isArray) {%>
@ -308,18 +332,16 @@ 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; // this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check // trap check
if(trap_state!=0){ if(trap_state!=0){
//In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval) super::core.enter_trap(trap_state, pc.val, instr);
auto mcause = (trap_state>>16) & 0xff;
super::core.enter_trap(trap_state, pc.val, mcause ? instr:tval);
} else { } else {
icount++; icount++;
instret++; instret++;
} }
*PC = *NEXT_PC; cycle++;
pc.val=*NEXT_PC;
this->core.reg.PC = this->core.reg.NEXT_PC;
this->core.reg.trap_state = this->core.reg.pending_trap; this->core.reg.trap_state = this->core.reg.pending_trap;
} }
fetch_count++;
cycle++;
} }
return pc; return pc;
} }
@ -335,30 +357,22 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} // namespace interp } // namespace interp
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h> #include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h> #include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss { namespace iss {
namespace { namespace {
volatile std::array<bool, 2> dummy = { volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); 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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}), }),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* 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); 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}) })
}; };

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2017-2024 MINRES Technologies GmbH * Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -36,10 +36,7 @@
#include <iss/iss.h> #include <iss/iss.h>
#include <iss/llvm/vm_base.h> #include <iss/llvm/vm_base.h>
#include <util/logging.h> #include <util/logging.h>
#include <iss/instruction_decoder.h>
<%def fcsr = registers.find {it.name=='FCSR'}
if(fcsr != null) {%>
#include <vm/fp_functions.h><%}%>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -85,9 +82,7 @@ protected:
using vm_base<ARCH>::get_reg_ptr; using vm_base<ARCH>::get_reg_ptr;
inline const char *name(size_t index){return traits::reg_aliases.at(index);} inline const char *name(size_t index){return traits::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) { template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits())); return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
} }
@ -104,14 +99,16 @@ protected:
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 &, unsigned int &, BasicBlock *) override;
void gen_leave_behavior(BasicBlock *leave_blk) override; void gen_leave_behavior(BasicBlock *leave_blk) override;
void gen_raise_trap(uint16_t trap_id, uint16_t cause); void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl); void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type); 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_behavior(BasicBlock *) override;
void gen_instr_prologue();
void gen_instr_epilogue(BasicBlock *bb); void gen_trap_check(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) { inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false); return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
@ -135,58 +132,51 @@ protected:
auto sign_mask = 1ULL<<(W-1); auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0); return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} }
<%functions.each{ it.eachLine { %>
${it}<%}%>
<%}%>
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct instruction_descriptor {
uint32_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
compile_func op; compile_func op;
}; };
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{ decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}}; }};
//needs to be declared after instr_descr
decoder instr_decoder;
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */ /* instruction ${idx}: ${instr.name} */
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
this->gen_sync(PRE_SYNC,${idx});
uint64_t PC = pc.val; uint64_t PC = pc.val;
<%instr.fields.eachLine{%>${it} <%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%> /* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%> ${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);
} }
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val)); auto cur_pc_val = this->gen_const(32,pc.val);
this->gen_sync(PRE_SYNC,${idx});
this->gen_set_pc(pc, traits::PC);
this->set_tval(instr);
pc=pc+ ${instr.length/8}; pc=pc+ ${instr.length/8};
this->gen_set_pc(pc, traits::NEXT_PC); this->gen_set_pc(pc, traits::NEXT_PC);
this->gen_instr_prologue();
/*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
this->gen_trap_check(bb);
this->gen_sync(POST_SYNC, ${idx}); this->gen_sync(POST_SYNC, ${idx});
this->gen_instr_epilogue(bb);
this->builder.CreateBr(bb); this->builder.CreateBr(bb);
return returnValue; return returnValue;
} }
@ -194,16 +184,7 @@ private:
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
std::tuple<continuation_e, BasicBlock *> illegal_instruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) { std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
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->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true), this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true),
get_reg_ptr(traits::PC), true); get_reg_ptr(traits::PC), true);
@ -212,13 +193,62 @@ private:
this->gen_const(64U, 1)), this->gen_const(64U, 1)),
get_reg_ptr(traits::ICOUNT), true); get_reg_ptr(traits::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->set_tval(instr);
this->gen_raise_trap(0, 2); // illegal instruction trap this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size()); this->gen_sync(iss::POST_SYNC, instr_descr.size());
bb = this->leave_blk; this->gen_trap_check(this->leave_blk);
this->gen_instr_epilogue(bb); return std::make_tuple(BRANCH, nullptr);
this->builder.CreateBr(bb); }
return std::make_tuple(ILLEGAL_INSTR, 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;
} }
}; };
@ -231,16 +261,13 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) : vm_base<ARCH>(core, core_id, cluster_id) {
, instr_decoder([this]() { root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
std::vector<generic_instruction_descriptor> g_instr_descr; for(auto instr:instr_descr){
g_instr_descr.reserve(instr_descr.size()); root->instrs.push_back(instr);
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}; populate_decoding_tree(root);
g_instr_descr.push_back(new_instr_descr);
} }
return std::move(g_instr_descr);
}()) {}
template <typename ARCH> template <typename ARCH>
std::tuple<continuation_e, BasicBlock *> std::tuple<continuation_e, BasicBlock *>
@ -253,82 +280,65 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
auto *const data = (uint8_t *)&instr; auto *const data = (uint8_t *)&instr;
if(this->core.has_mmu()) if(this->core.has_mmu())
paddr = this->core.virt2phys(pc); 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); auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
return std::make_tuple(ILLEGAL_FETCH, nullptr); // }
if (instr == 0x0000006f || (instr&0xffff)==0xa001) if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
return std::make_tuple(JUMP_TO_SELF, nullptr); // curr pc on stack
++inst_cnt; ++inst_cnt;
uint32_t inst_index = instr_decoder.decode_instr(instr); auto f = decode_instr(root, instr);
compile_func f = nullptr;
if(inst_index < instr_descr.size())
f = instr_descr[inst_index].op;
if (f == nullptr) { if (f == nullptr) {
f = &this_class::illegal_instruction; f = &this_class::illegal_intruction;
} }
return (this->*f)(pc, instr, this_block); return (this->*f)(pc, instr, this_block);
} }
template <typename ARCH> template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk); this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false)); this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false));
} }
template <typename ARCH> template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id); auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true); this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
this->builder.CreateBr(this->trap_blk); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
} }
template <typename ARCH> template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) }; std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args); this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
this->builder.CreateStore(this->gen_const(32U, static_cast<int>(UNKNOWN_JUMP)), get_reg_ptr(traits::LAST_BRANCH), false); 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);
} }
template <typename ARCH> template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args); this->builder.CreateCall(this->mod->getFunction("wait"), args);
} }
template <typename ARCH> template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
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->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); auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
auto *cur_pc_val = this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), true); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
std::vector<Value *> args{this->core_ptr, get_reg_ptr(traits::LAST_BRANCH), false);
this->adj_to64(trap_state_val), 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_typeptr(traits::PC), get_reg_ptr(traits::PC), false))};
this->adj_to64(this->builder.CreateLoad(this->get_type(64),this->tval))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); 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); 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); 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* 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); auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp( this->gen_cond_branch(this->builder.CreateICmp(
@ -336,10 +346,6 @@ void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
target_bb, this->trap_blk, 1); target_bb, this->trap_blk, 1);
this->builder.SetInsertPoint(target_bb); 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);
} }
} // namespace ${coreDef.name.toLowerCase()} } // namespace ${coreDef.name.toLowerCase()}
@ -353,30 +359,22 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} // namespace llvm } // namespace llvm
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h> #include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h> #include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss { namespace iss {
namespace { namespace {
volatile std::array<bool, 2> dummy = { volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}), }),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|llvm", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}) })
}; };

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2020-2024 MINRES Technologies GmbH * Copyright (C) 2020 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,10 +37,7 @@
#include <iss/tcc/vm_base.h> #include <iss/tcc/vm_base.h>
#include <util/logging.h> #include <util/logging.h>
#include <sstream> #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 #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -83,21 +80,16 @@ protected:
using vm_base<ARCH>::get_reg_ptr; using vm_base<ARCH>::get_reg_ptr;
using this_class = vm_impl<ARCH>; using this_class = vm_impl<ARCH>;
using compile_ret_t = continuation_e; using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
inline const char *name(size_t index){return traits::reg_aliases.at(index);} 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 { void setup_module(std::string m) override {
super::setup_module(m); super::setup_module(m);
} }
compile_ret_t gen_single_inst_behavior(virt_addr_t &, tu_builder&) override; compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, tu_builder&) override;
void gen_trap_behavior(tu_builder& tu) override; void gen_trap_behavior(tu_builder& tu) override;
@ -105,9 +97,7 @@ if(fcsr != null) {%>
void gen_leave_trap(tu_builder& tu, unsigned lvl); void gen_leave_trap(tu_builder& tu, unsigned lvl);
inline void gen_set_tval(tu_builder& tu, uint64_t new_tval); void gen_wait(tu_builder& tu, unsigned type);
inline void gen_set_tval(tu_builder& tu, value new_tval);
inline void gen_trap_check(tu_builder& tu) { inline void gen_trap_check(tu_builder& tu) {
tu("if(*trap_state!=0) goto trap_entry;"); tu("if(*trap_state!=0) goto trap_entry;");
@ -138,29 +128,32 @@ if(fcsr != null) {%>
return (from & mask) | ((from & sign_mask) ? ~mask : 0); return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} }
<%functions.each{ it.eachLine { %>
${it}<%}%>
<%}%>
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
****************************************************************************/ ****************************************************************************/
struct instruction_descriptor { struct instruction_descriptor {
uint32_t length; size_t length;
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
compile_func op; compile_func op;
}; };
struct decoding_tree_node{
std::vector<instruction_descriptor> instrs;
std::vector<decoding_tree_node*> children;
uint32_t submask = std::numeric_limits<uint32_t>::max();
uint32_t value;
decoding_tree_node(uint32_t value) : value(value){}
};
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{ decoding_tree_node* root {nullptr};
const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}}; }};
//needs to be declared after instr_descr
decoder instr_decoder;
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */ /* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
@ -171,36 +164,82 @@ private:
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%> /* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%> ${it}<%}%>
tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic);
} }
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]); auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
pc=pc+ ${instr.length/8}; pc=pc+ ${instr.length/8};
gen_set_pc(tu, pc, traits::NEXT_PC); gen_set_pc(tu, pc, traits::NEXT_PC);
tu.open_scope(); tu.open_scope();
this->gen_set_tval(tu, instr);
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
tu.close_scope(); tu.close_scope();
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
gen_trap_check(tu); gen_trap_check(tu);
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
return returnValue; return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
compile_ret_t illegal_instruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) {
vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size()); 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); pc = pc + ((instr & 3) == 3 ? 4 : 2);
gen_raise_trap(tu, 0, static_cast<int32_t>(traits:: RV_CAUSE_ILLEGAL_INSTRUCTION)); gen_raise_trap(tu, 0, 2); // illegal instruction trap
this->gen_set_tval(tu, instr);
vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size());
vm_impl::gen_trap_check(tu); vm_impl::gen_trap_check(tu);
return ILLEGAL_INSTR; 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;
} }
}; };
@ -213,102 +252,65 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
template <typename ARCH> template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) : vm_base<ARCH>(core, core_id, cluster_id) {
, instr_decoder([this]() { root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
std::vector<generic_instruction_descriptor> g_instr_descr; for(auto instr:instr_descr){
g_instr_descr.reserve(instr_descr.size()); root->instrs.push_back(instr);
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}; populate_decoding_tree(root);
g_instr_descr.push_back(new_instr_descr);
} }
return std::move(g_instr_descr);
}()) {}
template <typename ARCH> template <typename ARCH>
continuation_e std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, tu_builder& tu) { vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
// we fetch at max 4 byte, alignment is 2 // we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16}; enum {TRAP_ID=1<<16};
code_word_t instr = 0; code_word_t instr = 0;
phys_addr_t paddr(pc); phys_addr_t paddr(pc);
if(this->core.has_mmu()) if(this->core.has_mmu())
paddr = this->core.virt2phys(pc); 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)); auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
if (res != iss::Ok) if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
return ILLEGAL_FETCH; // }
if (instr == 0x0000006f || (instr&0xffff)==0xa001) if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
return JUMP_TO_SELF; // curr pc on stack
uint32_t inst_index = instr_decoder.decode_instr(instr); ++inst_cnt;
compile_func f = nullptr; auto f = decode_instr(root, instr);
if(inst_index < instr_descr.size())
f = instr_descr[inst_index].op;
if (f == nullptr) { if (f == nullptr) {
f = &this_class::illegal_instruction; f = &this_class::illegal_intruction;
} }
return (this->*f)(pc, instr, tu); return (this->*f)(pc, instr, tu);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) { template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
tu("leave_trap(core_ptr, {});", lvl); tu("leave_trap(core_ptr, {});", lvl);
tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN)); tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
tu.store(traits::LAST_BRANCH, tu.constant(static_cast<int>(UNKNOWN_JUMP), 32)); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_set_tval(tu_builder& tu, uint64_t new_tval) { template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
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) { template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
tu("trap_entry:"); tu("trap_entry:");
this->gen_sync(tu, POST_SYNC, -1); this->gen_sync(tu, POST_SYNC, -1);
tu("enter_trap(core_ptr, *trap_state, *pc, tval);"); tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
tu.store(traits::LAST_BRANCH, tu.constant(static_cast<int>(UNKNOWN_JUMP),32)); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
tu("return *next_pc;"); tu("return *next_pc;");
} }
<%
template <typename ARCH> void vm_impl<ARCH>::add_prologue(tu_builder& tu){
std::ostringstream os;
os << add_reg_ptr("trap_state", arch::traits<ARCH>::TRAP_STATE);
os << add_reg_ptr("pending_trap", arch::traits<ARCH>::PENDING_TRAP);
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()} } // namespace ${coreDef.name.toLowerCase()}
@ -321,30 +323,22 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} // namesapce tcc } // namesapce tcc
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h> #include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h> #include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss { namespace iss {
namespace { namespace {
volatile std::array<bool, 2> dummy = { volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false); auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port); 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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}), }),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void* init_data) -> std::tuple<cpu_ptr, vm_ptr>{ core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>(); auto* 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); 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 (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}}; return {cpu_ptr{cpu}, vm_ptr{vm}};
}) })
}; };

View File

@ -1,2 +0,0 @@
build/*/*.o
build/*/*.a

View File

@ -327,7 +327,7 @@ set(OTHERS
set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS}) set(LIB_SOURCES ${PRIMITIVES} ${SPECIALIZE} ${OTHERS})
add_library(softfloat STATIC ${LIB_SOURCES}) add_library(softfloat ${LIB_SOURCES})
set_property(TARGET softfloat PROPERTY C_STANDARD 99) set_property(TARGET softfloat PROPERTY C_STANDARD 99)
target_compile_definitions(softfloat PRIVATE target_compile_definitions(softfloat PRIVATE
SOFTFLOAT_ROUND_ODD SOFTFLOAT_ROUND_ODD
@ -347,7 +347,7 @@ set_target_properties(softfloat PROPERTIES
install(TARGETS softfloat install(TARGETS softfloat
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/static COMPONENT libs # static lib ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # shared lib
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # for mac 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) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel # headers for mac (note the different component -> different package)

View File

@ -1,24 +0,0 @@
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.

View File

@ -50,4 +50,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -50,4 +50,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -50,4 +50,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -1,399 +0,0 @@
#=============================================================================
#
# 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)

View File

@ -1,54 +0,0 @@
/*============================================================================
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"

View File

@ -94,8 +94,6 @@ OBJS_SPECIALIZE = \
s_f16UIToCommonNaN$(OBJ) \ s_f16UIToCommonNaN$(OBJ) \
s_commonNaNToF16UI$(OBJ) \ s_commonNaNToF16UI$(OBJ) \
s_propagateNaNF16UI$(OBJ) \ s_propagateNaNF16UI$(OBJ) \
s_bf16UIToCommonNaN$(OBJ) \
s_commonNaNToBF16UI$(OBJ) \
s_f32UIToCommonNaN$(OBJ) \ s_f32UIToCommonNaN$(OBJ) \
s_commonNaNToF32UI$(OBJ) \ s_commonNaNToF32UI$(OBJ) \
s_propagateNaNF32UI$(OBJ) \ s_propagateNaNF32UI$(OBJ) \
@ -116,8 +114,6 @@ OBJS_OTHERS = \
s_roundToUI64$(OBJ) \ s_roundToUI64$(OBJ) \
s_roundToI32$(OBJ) \ s_roundToI32$(OBJ) \
s_roundToI64$(OBJ) \ s_roundToI64$(OBJ) \
s_normSubnormalBF16Sig$(OBJ) \
s_roundPackToBF16$(OBJ) \
s_normSubnormalF16Sig$(OBJ) \ s_normSubnormalF16Sig$(OBJ) \
s_roundPackToF16$(OBJ) \ s_roundPackToF16$(OBJ) \
s_normRoundPackToF16$(OBJ) \ s_normRoundPackToF16$(OBJ) \
@ -176,8 +172,6 @@ OBJS_OTHERS = \
i64_to_extF80M$(OBJ) \ i64_to_extF80M$(OBJ) \
i64_to_f128$(OBJ) \ i64_to_f128$(OBJ) \
i64_to_f128M$(OBJ) \ i64_to_f128M$(OBJ) \
bf16_isSignalingNaN$(OBJ) \
bf16_to_f32$(OBJ) \
f16_to_ui32$(OBJ) \ f16_to_ui32$(OBJ) \
f16_to_ui64$(OBJ) \ f16_to_ui64$(OBJ) \
f16_to_i32$(OBJ) \ f16_to_i32$(OBJ) \
@ -215,7 +209,6 @@ OBJS_OTHERS = \
f32_to_ui64_r_minMag$(OBJ) \ f32_to_ui64_r_minMag$(OBJ) \
f32_to_i32_r_minMag$(OBJ) \ f32_to_i32_r_minMag$(OBJ) \
f32_to_i64_r_minMag$(OBJ) \ f32_to_i64_r_minMag$(OBJ) \
f32_to_bf16$(OBJ) \
f32_to_f16$(OBJ) \ f32_to_f16$(OBJ) \
f32_to_f64$(OBJ) \ f32_to_f64$(OBJ) \
f32_to_extF80$(OBJ) \ f32_to_extF80$(OBJ) \

View File

@ -50,4 +50,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -50,4 +50,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -51,4 +51,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define SOFTFLOAT_BUILTIN_CLZ 1 #define SOFTFLOAT_BUILTIN_CLZ 1
#define SOFTFLOAT_INTRINSIC_INT128 1 #define SOFTFLOAT_INTRINSIC_INT128 1
#include "opts-GCC.h" #include "opts-GCC.h"

View File

@ -115,8 +115,6 @@ OBJS_OTHERS = \
s_roundToUI64$(OBJ) \ s_roundToUI64$(OBJ) \
s_roundToI32$(OBJ) \ s_roundToI32$(OBJ) \
s_roundToI64$(OBJ) \ s_roundToI64$(OBJ) \
s_normSubnormalBF16Sig$(OBJ) \
s_roundPackToBF16$(OBJ) \
s_normSubnormalF16Sig$(OBJ) \ s_normSubnormalF16Sig$(OBJ) \
s_roundPackToF16$(OBJ) \ s_roundPackToF16$(OBJ) \
s_normRoundPackToF16$(OBJ) \ s_normRoundPackToF16$(OBJ) \
@ -175,8 +173,6 @@ OBJS_OTHERS = \
i64_to_extF80M$(OBJ) \ i64_to_extF80M$(OBJ) \
i64_to_f128$(OBJ) \ i64_to_f128$(OBJ) \
i64_to_f128M$(OBJ) \ i64_to_f128M$(OBJ) \
bf16_isSignalingNaN$(OBJ) \
bf16_to_f32$(OBJ) \
f16_to_ui32$(OBJ) \ f16_to_ui32$(OBJ) \
f16_to_ui64$(OBJ) \ f16_to_ui64$(OBJ) \
f16_to_i32$(OBJ) \ f16_to_i32$(OBJ) \
@ -214,7 +210,6 @@ OBJS_OTHERS = \
f32_to_ui64_r_minMag$(OBJ) \ f32_to_ui64_r_minMag$(OBJ) \
f32_to_i32_r_minMag$(OBJ) \ f32_to_i32_r_minMag$(OBJ) \
f32_to_i64_r_minMag$(OBJ) \ f32_to_i64_r_minMag$(OBJ) \
f32_to_bf16$(OBJ) \
f32_to_f16$(OBJ) \ f32_to_f16$(OBJ) \
f32_to_f64$(OBJ) \ f32_to_f64$(OBJ) \
f32_to_extF80$(OBJ) \ f32_to_extF80$(OBJ) \

View File

@ -47,4 +47,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define THREAD_LOCAL _Thread_local == > #define THREAD_LOCAL _Thread_local

View File

@ -47,4 +47,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
== > #define THREAD_LOCAL _Thread_local == > #define THREAD_LOCAL _Thread_local

View File

@ -508,7 +508,7 @@ significant extra cost.
On computers where the word size is <NOBR>64 bits</NOBR> or larger, both 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 function versions (<CODE>f128M_add</CODE> and <CODE>f128_add</CODE>) are
provided, because the cost of passing by value is then more reasonable. provided, because the cost of passing by value is then more reasonable.
Applications that must be portable across both classes of computers must use Applications that must be portable accross both classes of computers must use
the pointer-based functions, as these are always implemented. the pointer-based functions, as these are always implemented.
However, if it is known that SoftFloat includes the by-value functions for all However, if it is known that SoftFloat includes the by-value functions for all
platforms of interest, programmers can use whichever version they prefer. platforms of interest, programmers can use whichever version they prefer.

View File

@ -1,59 +0,0 @@
/*============================================================================
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;
}

View File

@ -1,51 +0,0 @@
/*============================================================================
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;
}

View File

@ -116,27 +116,6 @@ uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); 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. | The bit pattern for a default generated 32-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/

View File

@ -1,5 +0,0 @@
/*----------------------------------------------------------------------------
| This file intentionally contains no code.
*----------------------------------------------------------------------------*/

View File

@ -1,5 +0,0 @@
/*----------------------------------------------------------------------------
| This file intentionally contains no code.
*----------------------------------------------------------------------------*/

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: 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 <stdint.h>
#include "platform.h" #include "platform.h"
#include "softfloat_types.h" #include "internals.h"
#define softfloat_commonNaNToExtF80M softfloat_commonNaNToExtF80M
#include "specialize.h" #include "specialize.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -50,8 +49,8 @@ void
const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) const struct commonNaN *aPtr, struct extFloat80M *zSPtr )
{ {
zSPtr->signExp = defaultNaNExtF80UI64; zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF );
zSPtr->signif = defaultNaNExtF80UI0; zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: 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 <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "primitives.h"
#define softfloat_commonNaNToExtF80UI softfloat_commonNaNToExtF80UI
#include "specialize.h" #include "specialize.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -49,8 +48,8 @@ struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr )
{ {
struct uint128 uiZ; struct uint128 uiZ;
uiZ.v64 = defaultNaNExtF80UI64; uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF;
uiZ.v0 = defaultNaNExtF80UI0; uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1;
return uiZ; return uiZ;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -36,9 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "primitives.h"
#define softfloat_commonNaNToF128M softfloat_commonNaNToF128M
#include "specialize.h" #include "specialize.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -51,10 +49,8 @@ void
softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr )
{ {
zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr );
zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000;
zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32;
zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: 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 <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "primitives.h"
#define softfloat_commonNaNToF128UI softfloat_commonNaNToF128UI
#include "specialize.h" #include "specialize.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -48,8 +47,8 @@ struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr )
{ {
struct uint128 uiZ; struct uint128 uiZ;
uiZ.v64 = defaultNaNF128UI64; uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 );
uiZ.v0 = defaultNaNF128UI0; uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 );
return uiZ; return uiZ;
} }

View File

@ -1,5 +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 <stdint.h>
#include "platform.h"
#include "specialize.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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 )
{
return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54;
}

View File

@ -1,5 +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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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 )
{
return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41;
}

View File

@ -1,5 +1,53 @@
/*============================================================================
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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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 )
{
return
(uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 )
| aPtr->v64>>12;
}

View File

@ -1,5 +1,62 @@
/*============================================================================
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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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;
}

View File

@ -1,5 +1,62 @@
/*============================================================================
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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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;
}

View File

@ -1,5 +1,62 @@
/*============================================================================
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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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 );
}

View File

@ -1,5 +1,65 @@
/*============================================================================
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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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;
}

View File

@ -1,5 +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, 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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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 )
{
if ( softfloat_isSigNaNF16UI( uiA ) ) {
softfloat_raiseFlags( softfloat_flag_invalid );
}
zPtr->sign = uiA>>15;
zPtr->v64 = (uint_fast64_t) uiA<<54;
zPtr->v0 = 0;
}

View File

@ -1,5 +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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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;
}

View File

@ -1,5 +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"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| This file intentionally contains no code. | 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.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
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;
}

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: 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 <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
@ -53,22 +54,54 @@ void
struct extFloat80M *zSPtr struct extFloat80M *zSPtr
) )
{ {
uint_fast16_t ui64; bool isSigNaNA;
uint_fast64_t ui0; 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;
ui64 = aSPtr->signExp; isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr );
ui0 = aSPtr->signif; sPtr = aSPtr;
if ( if ( ! bSPtr ) {
softfloat_isSigNaNExtF80UI( ui64, ui0 ) if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid );
|| (bSPtr goto copy;
&& (ui64 = bSPtr->signExp, }
ui0 = bSPtr->signif, isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr );
softfloat_isSigNaNExtF80UI( ui64, ui0 ))) if ( isSigNaNA | isSigNaNB ) {
) {
softfloat_raiseFlags( softfloat_flag_invalid ); 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;
} }
zSPtr->signExp = defaultNaNExtF80UI64; }
zSPtr->signif = defaultNaNExtF80UI0; 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 );
} }

View File

@ -4,7 +4,7 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of
California. All rights reserved. California. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -34,16 +34,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating `uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
| `uiA0' as an 80-bit extended floating-point value, and likewise interpreting | 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting
| the unsigned integer formed from concatenating `uiB64' and `uiB0' as another | the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another
| 80-bit extended floating-point value, and assuming at least on of these | 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 | 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 | result. If either original floating-point value is a signaling NaN, the
@ -57,16 +58,48 @@ struct uint128
uint_fast64_t uiB0 uint_fast64_t uiB0
) )
{ {
bool isSigNaNA, isSigNaNB;
uint_fast64_t uiNonsigA0, uiNonsigB0;
uint_fast16_t uiMagA64, uiMagB64;
struct uint128 uiZ; struct uint128 uiZ;
if ( /*------------------------------------------------------------------------
softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) *------------------------------------------------------------------------*/
|| softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) 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 ) {
softfloat_raiseFlags( softfloat_flag_invalid ); 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;
} }
uiZ.v64 = defaultNaNExtF80UI64; }
uiZ.v0 = defaultNaNExtF80UI0; 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;
return uiZ; return uiZ;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015, 2018 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -34,35 +34,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 128-bit floating-point values pointed to by | 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 | `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 | pointed to by `zWPtr'. If either original floating-point value is a
| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', | 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 | 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. | the platform's normal endian order to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
softfloat_propagateNaNF128M( softfloat_propagateNaNF128M(
const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) 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 ( if (
f128M_isSignalingNaN( (const float128_t *) aWPtr ) isSigNaNA
|| (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr ))
) { ) {
softfloat_raiseFlags( softfloat_flag_invalid ); softfloat_raiseFlags( softfloat_flag_invalid );
if ( isSigNaNA ) goto copy;
} }
zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr;
zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; copy:
zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000;
zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )];
zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )];
zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )];
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: 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 <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "primitiveTypes.h" #include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
@ -57,16 +58,23 @@ struct uint128
uint_fast64_t uiB0 uint_fast64_t uiB0
) )
{ {
bool isSigNaNA;
struct uint128 uiZ; struct uint128 uiZ;
if ( isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 );
softfloat_isSigNaNF128UI( uiA64, uiA0 ) if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) {
|| softfloat_isSigNaNF128UI( uiB64, uiB0 )
) {
softfloat_raiseFlags( softfloat_flag_invalid ); softfloat_raiseFlags( softfloat_flag_invalid );
if ( isSigNaNA ) goto returnNonsigA;
} }
uiZ.v64 = defaultNaNF128UI64; if ( isNaNF128UI( uiA64, uiA0 ) ) {
uiZ.v0 = defaultNaNF128UI0; returnNonsigA:
uiZ.v64 = uiA64;
uiZ.v0 = uiA0;
} else {
uiZ.v64 = uiB64;
uiZ.v0 = uiB0;
}
uiZ.v64 |= UINT64_C( 0x0000800000000000 );
return uiZ; return uiZ;
} }

View File

@ -4,7 +4,7 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of
California. All rights reserved. California. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -34,8 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
@ -48,11 +50,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
uint_fast16_t uint_fast16_t
softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB )
{ {
bool isSigNaNA;
if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { isSigNaNA = softfloat_isSigNaNF16UI( uiA );
if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) {
softfloat_raiseFlags( softfloat_flag_invalid ); softfloat_raiseFlags( softfloat_flag_invalid );
if ( isSigNaNA ) return uiA | 0x0200;
} }
return defaultNaNF16UI; return (isNaNF16UI( uiA ) ? uiA : uiB) | 0x0200;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -34,8 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
@ -48,11 +50,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
uint_fast32_t uint_fast32_t
softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB )
{ {
bool isSigNaNA;
if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) { isSigNaNA = softfloat_isSigNaNF32UI( uiA );
if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) {
softfloat_raiseFlags( softfloat_flag_invalid ); softfloat_raiseFlags( softfloat_flag_invalid );
if ( isSigNaNA ) return uiA | 0x00400000;
} }
return defaultNaNF32UI; return (isNaNF32UI( uiA ) ? uiA : uiB) | 0x00400000;
} }

View File

@ -4,8 +4,8 @@
This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser. Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of Copyright 2011, 2012, 2013, 2014 The Regents of the University of California.
California. All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -34,8 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/ =============================================================================*/
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "internals.h"
#include "specialize.h" #include "specialize.h"
#include "softfloat.h" #include "softfloat.h"
@ -48,11 +50,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
uint_fast64_t uint_fast64_t
softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB )
{ {
bool isSigNaNA;
if ( softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) ) { isSigNaNA = softfloat_isSigNaNF64UI( uiA );
if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) {
softfloat_raiseFlags( softfloat_flag_invalid ); softfloat_raiseFlags( softfloat_flag_invalid );
if ( isSigNaNA ) return uiA | UINT64_C( 0x0008000000000000 );
} }
return defaultNaNF64UI; return (isNaNF64UI( uiA ) ? uiA : uiB) | UINT64_C( 0x0008000000000000 );
} }

View File

@ -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 | The values to return on conversions to 32-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromPosOverflow UINT32_C(0xFFFFFFFF)
#define ui32_fromNegOverflow 0 #define ui32_fromNegOverflow UINT32_C(0x0)
#define ui32_fromNaN 0xFFFFFFFF #define ui32_fromNaN UINT32_C(0xFFFFFFFF)
#define i32_fromPosOverflow 0x7FFFFFFF #define i32_fromPosOverflow INT64_C(0x7FFFFFFF)
#define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNegOverflow (-INT64_C(0x7FFFFFFF) - 1)
#define i32_fromNaN 0x7FFFFFFF #define i32_fromNaN INT64_C(0x7FFFFFFF)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The values to return on conversions to 64-bit integer formats that raise an | The values to return on conversions to 64-bit integer formats that raise an
| invalid exception. | invalid exception.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromPosOverflow UINT64_C(0xFFFFFFFFFFFFFFFF)
#define ui64_fromNegOverflow 0 #define ui64_fromNegOverflow UINT64_C(0x0)
#define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF) #define ui64_fromNaN UINT64_C(0xFFFFFFFFFFFFFFFF)
#define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF) #define i64_fromPosOverflow INT64_C(0x7FFFFFFFFFFFFFFF)
#define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1) #define i64_fromNegOverflow (-INT64_C(0x7FFFFFFFFFFFFFFF) - 1)
@ -74,13 +74,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
| to another. | to another.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
struct commonNaN { struct commonNaN {
char _unused; bool sign;
#ifdef LITTLEENDIAN
uint64_t v0, v64;
#else
uint64_t v64, v0;
#endif
}; };
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 16-bit floating-point NaN. | The bit pattern for a default generated 16-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF16UI 0x7E00 #define defaultNaNF16UI 0xFE00
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a | Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a
@ -89,38 +94,19 @@ struct commonNaN {
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_isSigNaNF16UI(uiA) ((((uiA)&0x7E00) == 0x7C00) && ((uiA)&0x01FF)) #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 | 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 | 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 | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f16UIToCommonNaN(uiA, zPtr) \ void softfloat_f16UIToCommonNaN(uint_fast16_t uiA, struct commonNaN* 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 | 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. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF16UI(aPtr) ((uint_fast16_t)defaultNaNF16UI) uint_fast16_t softfloat_commonNaNToF16UI(const struct commonNaN* aPtr);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating-
@ -130,17 +116,6 @@ struct commonNaN {
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
uint_fast16_t softfloat_propagateNaNF16UI(uint_fast16_t uiA, uint_fast16_t uiB); 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. | The bit pattern for a default generated 32-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -159,15 +134,13 @@ 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 | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f32UIToCommonNaN(uiA, zPtr) \ void softfloat_f32UIToCommonNaN(uint_fast32_t uiA, struct commonNaN* zPtr);
if(!((uiA)&0x00400000)) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point | 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. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF32UI(aPtr) ((uint_fast32_t)defaultNaNF32UI) uint_fast32_t softfloat_commonNaNToF32UI(const struct commonNaN* aPtr);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@ -196,15 +169,13 @@ 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 | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f64UIToCommonNaN(uiA, zPtr) \ void softfloat_f64UIToCommonNaN(uint_fast64_t uiA, struct commonNaN* 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 | 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. | NaN, and returns the bit pattern of this value as an unsigned integer.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_commonNaNToF64UI(aPtr) ((uint_fast64_t)defaultNaNF64UI) uint_fast64_t softfloat_commonNaNToF64UI(const struct commonNaN* aPtr);
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- | Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating-
@ -217,7 +188,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. | The bit pattern for a default generated 80-bit extended floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNExtF80UI64 0x7FFF #define defaultNaNExtF80UI64 0xFFFF
#define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000) #define defaultNaNExtF80UI0 UINT64_C(0xC000000000000000)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -243,26 +214,14 @@ 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 | location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
| exception is raised. | exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_extF80UIToCommonNaN(uiA64, uiA0, zPtr) \ void softfloat_extF80UIToCommonNaN(uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN* zPtr);
if(!((uiA0)&UINT64_C(0x4000000000000000))) \
softfloat_raiseFlags(softfloat_flag_invalid)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended | 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 | floating-point NaN, and returns the bit pattern of this value as an unsigned
| integer. | 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); struct uint128 softfloat_commonNaNToExtF80UI(const struct commonNaN* aPtr);
#endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -278,7 +237,7 @@ struct uint128 softfloat_propagateNaNExtF80UI(uint_fast16_t uiA64, uint_fast64_t
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI64 UINT64_C(0x7FFF800000000000) #define defaultNaNF128UI64 UINT64_C(0xFFFF800000000000)
#define defaultNaNF128UI0 UINT64_C(0) #define defaultNaNF128UI0 UINT64_C(0)
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -297,25 +256,13 @@ 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 | pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception
| is raised. | is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f128UIToCommonNaN(uiA64, uiA0, zPtr) \ void softfloat_f128UIToCommonNaN(uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN* 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 | 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. | 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*); struct uint128 softfloat_commonNaNToF128UI(const struct commonNaN*);
#endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Interpreting the unsigned integer formed from concatenating 'uiA64' and | Interpreting the unsigned integer formed from concatenating 'uiA64' and
@ -341,24 +288,14 @@ 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 | common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling
| NaN, the invalid exception is raised. | NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_extF80MToCommonNaN(aSPtr, zPtr) \ void softfloat_extF80MToCommonNaN(const struct extFloat80M* aSPtr, struct commonNaN* 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 | 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 | floating-point NaN, and stores this NaN at the location pointed to by
| 'zSPtr'. | '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); void softfloat_commonNaNToExtF80M(const struct commonNaN* aPtr, struct extFloat80M* zSPtr);
#endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Assuming at least one of the two 80-bit extended floating-point values | Assuming at least one of the two 80-bit extended floating-point values
@ -371,7 +308,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| The bit pattern for a default generated 128-bit floating-point NaN. | The bit pattern for a default generated 128-bit floating-point NaN.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define defaultNaNF128UI96 0x7FFF8000 #define defaultNaNF128UI96 0xFFFF8000
#define defaultNaNF128UI64 0 #define defaultNaNF128UI64 0
#define defaultNaNF128UI32 0 #define defaultNaNF128UI32 0
#define defaultNaNF128UI0 0 #define defaultNaNF128UI0 0
@ -384,9 +321,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| four 32-bit elements that concatenate in the platform's normal endian order | four 32-bit elements that concatenate in the platform's normal endian order
| to form a 128-bit floating-point value. | to form a 128-bit floating-point value.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define softfloat_f128MToCommonNaN(aWPtr, zPtr) \ void softfloat_f128MToCommonNaN(const uint32_t* aWPtr, struct commonNaN* 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 | Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point
@ -394,17 +329,7 @@ void softfloat_propagateNaNExtF80M(const struct extFloat80M* aSPtr, const struct
| 'zWPtr' points to an array of four 32-bit elements that concatenate in the | '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. | 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); 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 | Assuming at least one of the two 128-bit floating-point values pointed to by

View File

@ -1,51 +0,0 @@
/*============================================================================
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 );
}

View File

@ -1,90 +0,0 @@
/*============================================================================
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;
}

View File

@ -1,105 +0,0 @@
/*============================================================================
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;
}

View File

@ -72,9 +72,6 @@ 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); frac16 = frac>>9 | ((frac & 0x1FF) != 0);
if ( ! (exp | frac16) ) { if ( ! (exp | frac16) ) {
uiZ = packToF16UI( sign, 0, 0 ); uiZ = packToF16UI( sign, 0, 0 );

View File

@ -46,10 +46,6 @@ union ui16_f16 {
uint16_t ui; uint16_t ui;
float16_t f; float16_t f;
}; };
union ui16_bf16 {
uint16_t ui;
bfloat16_t f;
};
union ui32_f32 { union ui32_f32 {
uint32_t ui; uint32_t ui;
float32_t f; float32_t f;
@ -112,18 +108,6 @@ float16_t softfloat_addMagsF16(uint_fast16_t, uint_fast16_t);
float16_t softfloat_subMagsF16(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); 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)) #define signF32UI(a) ((bool)((uint32_t)(a) >> 31))

View File

@ -76,13 +76,13 @@ enum {
| Software floating-point exception flags. | Software floating-point exception flags.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags;
typedef enum { enum {
softfloat_flag_inexact = 1, softfloat_flag_inexact = 1,
softfloat_flag_underflow = 2, softfloat_flag_underflow = 2,
softfloat_flag_overflow = 4, softfloat_flag_overflow = 4,
softfloat_flag_infinite = 8, softfloat_flag_infinite = 8,
softfloat_flag_invalid = 16 softfloat_flag_invalid = 16
} exceptionFlag_t; };
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
| Routine to raise any or all of the software floating-point exception flags. | Routine to raise any or all of the software floating-point exception flags.
@ -164,13 +164,6 @@ bool f16_le_quiet(float16_t, float16_t);
bool f16_lt_quiet(float16_t, float16_t); bool f16_lt_quiet(float16_t, float16_t);
bool f16_isSignalingNaN(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. | 32-bit (single-precision) floating-point operations.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/

View File

@ -50,9 +50,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
typedef struct { typedef struct {
uint16_t v; uint16_t v;
} float16_t; } float16_t;
typedef struct {
uint16_t v;
} bfloat16_t;
typedef struct { typedef struct {
uint32_t v; uint32_t v;
} float32_t; } float32_t;

View File

@ -221,3 +221,4 @@ float32_t
return uZ.f; return uZ.f;
} }

View File

@ -1,52 +0,0 @@
/*============================================================================
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;
}

View File

@ -1,114 +0,0 @@
/*============================================================================
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;
}

View File

@ -1,35 +0,0 @@
#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;
}

View File

@ -51,8 +51,8 @@ public:
virtual ~hwl() = default; virtual ~hwl() = default;
protected: protected:
iss::status read_custom_csr(unsigned addr, reg_t& val) override; iss::status read_custom_csr_reg(unsigned addr, reg_t& val) override;
iss::status write_custom_csr(unsigned addr, reg_t val) override; iss::status write_custom_csr_reg(unsigned addr, reg_t val) override;
}; };
template <typename BASE> 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(unsigned addr, reg_t& val) { template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t& val) {
switch(addr) { switch(addr) {
case 0x800: case 0x800:
val = this->reg.lpstart0; val = this->reg.lpstart0;
@ -92,7 +92,7 @@ template <typename BASE> inline iss::status iss::arch::hwl<BASE>::read_custom_cs
return iss::Ok; return iss::Ok;
} }
template <typename BASE> inline iss::status iss::arch::hwl<BASE>::write_custom_csr(unsigned addr, reg_t val) { template <typename BASE> inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
switch(addr) { switch(addr) {
case 0x800: case 0x800:
this->reg.lpstart0 = val; this->reg.lpstart0 = val;

View File

@ -35,23 +35,8 @@
#ifndef _RISCV_HART_COMMON #ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON #define _RISCV_HART_COMMON
#include "iss/vm_types.h" #include "iss/arch_if.h"
#include <cstdint> #include <cstdint>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iss/arch_if.h>
#include <iss/log_categories.h>
#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 iss {
namespace arch { namespace arch {
@ -311,73 +296,6 @@ inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t* const
break; break;
} }
} }
struct riscv_hart_common {
riscv_hart_common(){};
~riscv_hart_common(){};
std::unordered_map<std::string, uint64_t> symbol_table;
uint64_t entry_address{0};
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
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");
try {
fromhost = symbol_table.at("fromhost");
} catch(std::out_of_range& e) {
fromhost = tohost + 0x40;
}
} catch(std::out_of_range& e) {
}
}
return true;
}
return false;
};
};
} // namespace arch } // namespace arch
} // namespace iss } // namespace iss

View File

@ -39,10 +39,7 @@
#include "iss/instrumentation_if.h" #include "iss/instrumentation_if.h"
#include "iss/log_categories.h" #include "iss/log_categories.h"
#include "iss/vm_if.h" #include "iss/vm_if.h"
#include "iss/vm_types.h"
#include "riscv_hart_common.h" #include "riscv_hart_common.h"
#include <elfio/elf_types.hpp>
#include <stdexcept>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -58,13 +55,18 @@
#include <util/ities.h> #include <util/ities.h>
#include <util/sparse_array.h> #include <util/sparse_array.h>
#include <iss/semihosting/semihosting.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 iss {
namespace arch { namespace arch {
template <typename BASE, features_e FEAT = FEAT_NONE, typename LOGCAT = logging::disass> template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_m_p : public BASE {
class riscv_hart_m_p : public BASE, public riscv_hart_common {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -91,7 +93,7 @@ protected:
public: public:
using core = BASE; using core = BASE;
using this_class = riscv_hart_m_p<BASE, FEAT, LOGCAT>; using this_class = riscv_hart_m_p<BASE, FEAT>;
using phys_addr_t = typename core::phys_addr_t; using phys_addr_t = typename core::phys_addr_t;
using reg_t = typename core::reg_t; using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t; using addr_t = typename core::addr_t;
@ -278,8 +280,8 @@ public:
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", pc, instr, (reg_t)state.mstatus, CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", pc, instr, (reg_t)state.mstatus,
this->reg.cycle + cycle_offset); this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
@ -288,12 +290,10 @@ public:
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } 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: protected:
struct riscv_instrumentation_if : public iss::instrumentation_if { struct riscv_instrumentation_if : public iss::instrumentation_if {
riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch) riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT>& arch)
: arch(arch) {} : arch(arch) {}
/** /**
* get the name of this architecture * get the name of this architecture
@ -312,7 +312,7 @@ protected:
uint64_t get_pendig_traps() override { return arch.reg.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
@ -322,9 +322,7 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } 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_m_p<BASE, FEAT>& arch;
riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch;
}; };
friend struct riscv_instrumentation_if; friend struct riscv_instrumentation_if;
@ -344,11 +342,11 @@ protected:
int64_t instret_offset{0}; int64_t instret_offset{0};
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
bool tohost_lower_written = false; uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
unsigned to_host_wr_cnt = 0;
riscv_instrumentation_if instr_if; riscv_instrumentation_if instr_if;
semihosting_cb_t<reg_t> semihosting_cb;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; 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_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
using csr_page_type = typename csr_type::page_type; using csr_page_type = typename csr_type::page_type;
@ -376,8 +374,8 @@ protected:
std::vector<uint8_t> tcm; std::vector<uint8_t> tcm;
iss::status read_plain(unsigned addr, reg_t& val); iss::status read_csr_reg(unsigned addr, reg_t& val);
iss::status write_plain(unsigned addr, reg_t val); iss::status write_csr_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t& val); iss::status read_null(unsigned addr, reg_t& val);
iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; }
iss::status read_cycle(unsigned addr, reg_t& val); iss::status read_cycle(unsigned addr, reg_t& val);
@ -398,19 +396,17 @@ protected:
iss::status read_intstatus(unsigned addr, reg_t& val); iss::status read_intstatus(unsigned addr, reg_t& val);
iss::status write_intthresh(unsigned addr, reg_t val); iss::status write_intthresh(unsigned addr, reg_t val);
iss::status write_xtvt(unsigned addr, reg_t val); iss::status write_xtvt(unsigned addr, reg_t val);
iss::status write_dcsr(unsigned addr, reg_t val); iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
iss::status read_debug(unsigned addr, reg_t& val); iss::status read_dcsr_reg(unsigned addr, reg_t& val);
iss::status write_dscratch(unsigned addr, reg_t val); iss::status write_dcsr_reg(unsigned addr, reg_t val);
iss::status read_dpc(unsigned addr, reg_t& val); iss::status read_dpc_reg(unsigned addr, reg_t& val);
iss::status write_dpc(unsigned addr, reg_t val); iss::status write_dpc_reg(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(unsigned addr, reg_t& val) { return iss::status::Err; }; virtual iss::status read_custom_csr_reg(unsigned addr, reg_t& val) { return iss::status::Err; };
virtual iss::status write_custom_csr(unsigned addr, reg_t val) { return iss::status::Err; }; virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) { return iss::status::Err; };
void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr; } 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; } void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr_reg; }
reg_t mhartid_reg{0x0}; reg_t mhartid_reg{0x0};
@ -423,7 +419,6 @@ protected:
feature_config cfg; feature_config cfg;
unsigned mcause_max_irq{(FEAT & features_e::FEAT_CLIC) ? std::max(16U, static_cast<unsigned>(traits<BASE>::CLIC_NUM_IRQ)) : 16U}; 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; } 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::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::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}; std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
@ -435,8 +430,8 @@ protected:
std::function<mem_write_f> hart_mem_wr_delegate; std::function<mem_write_f> hart_mem_wr_delegate;
}; };
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg) riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
: state() : state()
, instr_if(*this) , instr_if(*this)
, cfg(cfg) { , cfg(cfg) {
@ -447,22 +442,18 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
csr[mimpid] = 1; csr[mimpid] = 1;
uart_buf.str(""); 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) { for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
if(traits<BASE>::XLEN == 32) if(traits<BASE>::XLEN == 32)
for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
@ -470,17 +461,18 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
if(traits<BASE>::XLEN == 32) if(traits<BASE>::XLEN == 32)
for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) { for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
// csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// common regs // common regs
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}}; const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
for(auto addr : roaddrs) { for(auto addr : roaddrs) {
csr_rd_cb[addr] = &this_class::read_plain; csr_rd_cb[addr] = &this_class::read_csr_reg;
csr_wr_cb[addr] = &this_class::write_null; csr_wr_cb[addr] = &this_class::write_null;
} }
const std::array<unsigned, 4> rwaddrs{{mepc, mtvec, mscratch, mtval}}; const std::array<unsigned, 4> rwaddrs{{mepc, mtvec, mscratch, mtval}};
for(auto addr : rwaddrs) { for(auto addr : rwaddrs) {
csr_rd_cb[addr] = &this_class::read_plain; csr_rd_cb[addr] = &this_class::read_csr_reg;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// special handling & overrides // special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
@ -521,7 +513,7 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
csr_wr_cb[marchid] = &this_class::write_null; csr_wr_cb[marchid] = &this_class::write_null;
csr_wr_cb[mimpid] = &this_class::write_null; csr_wr_cb[mimpid] = &this_class::write_null;
if(FEAT & FEAT_CLIC) { if(FEAT & FEAT_CLIC) {
csr_rd_cb[mtvt] = &this_class::read_plain; csr_rd_cb[mtvt] = &this_class::read_csr_reg;
csr_wr_cb[mtvt] = &this_class::write_xtvt; csr_wr_cb[mtvt] = &this_class::write_xtvt;
// csr_rd_cb[mxnti] = &this_class::read_csr_reg; // csr_rd_cb[mxnti] = &this_class::read_csr_reg;
// csr_wr_cb[mxnti] = &this_class::write_csr_reg; // csr_wr_cb[mxnti] = &this_class::write_csr_reg;
@ -531,7 +523,7 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
// csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg; // csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
// csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg; // csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
// csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg; // csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
csr_rd_cb[mintthresh] = &this_class::read_plain; csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
csr_wr_cb[mintthresh] = &this_class::write_intthresh; csr_wr_cb[mintthresh] = &this_class::write_intthresh;
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0}); clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0});
clic_cfg_reg = 0x20; clic_cfg_reg = 0x20;
@ -557,33 +549,88 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb); insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
} }
if(FEAT & FEAT_DEBUG) { if(FEAT & FEAT_DEBUG) {
csr_wr_cb[dscratch0] = &this_class::write_dscratch; csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
csr_rd_cb[dscratch0] = &this_class::read_debug; csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
csr_wr_cb[dscratch1] = &this_class::write_dscratch; csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
csr_rd_cb[dscratch1] = &this_class::read_debug; csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
csr_wr_cb[dpc] = &this_class::write_dpc; csr_wr_cb[dpc] = &this_class::write_dpc_reg;
csr_rd_cb[dpc] = &this_class::read_dpc; csr_rd_cb[dpc] = &this_class::read_dpc_reg;
csr_wr_cb[dcsr] = &this_class::write_dcsr; csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
csr_rd_cb[dcsr] = &this_class::read_debug; csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
} }
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return this->read_mem(a, l, d); }; hart_mem_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); }; 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, typename LOGCAT> template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) { FILE* fp = fopen(name.c_str(), "r");
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, if(fp) {
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { std::array<char, 5> buf;
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size, auto n = fread(buf.data(), 1, 4, fp);
data); fclose(fp);
})) { if(n != 4)
return std::make_pair(entry_address, true); 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();
} }
return std::make_pair(entry_address, false); }
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));
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
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, inline void riscv_hart_m_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
std::function<mem_write_f> wr_fn) { std::function<mem_write_f> wr_fn) {
std::tuple<uint64_t, uint64_t> entry{base, size}; std::tuple<uint64_t, uint64_t> entry{base, size};
auto it = std::upper_bound( auto it = std::upper_bound(
@ -595,16 +642,16 @@ inline void riscv_hart_m_p<BASE, FEAT, LOGCAT>::insert_mem_range(uint64_t base,
memfn_write.insert(std::begin(memfn_write) + idx, wr_fn); memfn_write.insert(std::begin(memfn_write) + idx, wr_fn);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read(const address_type type, const access_type access, const uint32_t space, iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr,
const uint64_t addr, const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH) { } else if(access && iss::access_type::FETCH) {
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -626,7 +673,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read(const address_type type, co
} }
phys_addr_t phys_addr{access, space, addr}; phys_addr_t phys_addr{access, space, addr};
auto res = iss::Err; auto res = iss::Err;
if(!is_fetch(access) && memfn_range.size()) { if(access != access_type::FETCH && memfn_range.size()) {
auto it = auto it =
std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a) { 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; return std::get<0>(a) <= phys_addr.val && (std::get<0>(a) + std::get<1>(a)) > phys_addr.val;
@ -645,10 +692,8 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read(const address_type type, co
} }
return res; return res;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} break; } break;
@ -675,38 +720,36 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read(const address_type type, co
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, const access_type access, const uint32_t space, 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 uint64_t addr, const unsigned length, const uint8_t* const data) { const unsigned length, const uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -727,7 +770,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, c
} }
phys_addr_t phys_addr{access, space, addr}; phys_addr_t phys_addr{access, space, addr};
auto res = iss::Err; auto res = iss::Err;
if(!is_fetch(access) && memfn_range.size()) { if(access != access_type::FETCH && memfn_range.size()) {
auto it = auto it =
std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a) { 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; return std::get<0>(a) <= phys_addr.val && (std::get<0>(a) + std::get<1>(a)) > phys_addr.val;
@ -741,7 +784,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, c
res = write_mem(phys_addr, length, data); res = write_mem(phys_addr, length, data);
} }
if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) {
this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data = addr; fault_data = addr;
} }
return res; return res;
@ -758,6 +801,8 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, c
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
} }
@ -808,16 +853,13 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write(const address_type type, c
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t& val) {
if(addr >= csr.size()) if(addr >= csr.size())
return iss::Err; return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
@ -829,8 +871,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t& v
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t val) {
if(addr >= csr.size()) if(addr >= csr.size())
return iss::Err; return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
@ -844,27 +885,23 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t v
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t& val) {
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, typename LOGCAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_plain(unsigned addr, reg_t& val) {
val = csr[addr]; val = csr[addr];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_null(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_plain(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) {
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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) { if(addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if(addr == mcycleh) { } else if(addr == mcycleh) {
@ -873,8 +910,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_cycle(unsigned addr, reg_t&
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_t val) {
if(sizeof(typename traits<BASE>::reg_t) != 4) { if(sizeof(typename traits<BASE>::reg_t) != 4) {
mcycle_csr = static_cast<uint64_t>(val); mcycle_csr = static_cast<uint64_t>(val);
} else { } else {
@ -884,12 +920,11 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_t
mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff); mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around cycle_offset = mcycle_csr - this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg_t& val) {
if((addr & 0xff) == (minstret & 0xff)) { if((addr & 0xff) == (minstret & 0xff)) {
val = static_cast<reg_t>(this->reg.instret); val = static_cast<reg_t>(this->reg.instret);
} else if((addr & 0xff) == (minstreth & 0xff)) { } else if((addr & 0xff) == (minstreth & 0xff)) {
@ -898,8 +933,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg_
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, reg_t val) {
if(sizeof(typename traits<BASE>::reg_t) != 4) { if(sizeof(typename traits<BASE>::reg_t) != 4) {
this->reg.instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
@ -913,9 +947,8 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, reg
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::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) { if(addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if(addr == timeh) { } else if(addr == timeh) {
@ -926,27 +959,23 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_time(unsigned addr, reg_t&
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t& val) {
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; val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_status(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_status(unsigned addr, reg_t& val) {
val = state.mstatus & hart_state_type::get_mask(); val = state.mstatus & hart_state_type::get_mask();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_status(unsigned addr, reg_t val) {
state.write_mstatus(val); state.write_mstatus(val);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t& val) {
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) { 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 = csr[addr] & ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
val |= clic_mprev_lvl << 16; val |= clic_mprev_lvl << 16;
@ -957,8 +986,7 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_cause(unsigned addr, reg_t&
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
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) { if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) {
auto mask = ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); auto mask = ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
csr[addr] = (val & mask) | (csr[addr] & ~mask); csr[addr] = (val & mask) | (csr[addr] & ~mask);
@ -972,42 +1000,36 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_cause(unsigned addr, reg_t
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_hartid(unsigned addr, reg_t& val) {
val = mhartid_reg; val = mhartid_reg;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ie(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_ie(unsigned addr, reg_t& val) {
auto mask = get_irq_mask(); auto mask = get_irq_mask();
val = csr[mie] & mask; val = csr[mie] & mask;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_ie(unsigned addr, reg_t val) {
auto mask = get_irq_mask(); auto mask = get_irq_mask();
csr[mie] = (csr[mie] & ~mask) | (val & mask); csr[mie] = (csr[mie] & ~mask) | (val & mask);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ip(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_ip(unsigned addr, reg_t& val) {
auto mask = get_irq_mask(); auto mask = get_irq_mask();
val = csr[mip] & mask; val = csr[mip] & mask;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask(); csr[addr] = val & get_pc_mask();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_dcsr(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
// +-------------- ebreakm // +-------------- ebreakm
@ -1018,70 +1040,51 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_debug(unsigned addr, reg_t& val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
val = csr[addr]; val = csr[addr];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dscratch(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_dpc(unsigned addr, reg_t& val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
val = this->reg.DPC; val = this->reg.DPC;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_dpc(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
this->reg.DPC = val; this->reg.DPC = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_intstatus(unsigned addr, reg_t& val) {
val = (clic_mact_lvl & 0xff) << 24; val = (clic_mact_lvl & 0xff) << 24;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
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; csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_xtvt(unsigned addr, reg_t val) {
csr[addr] = val & ~0x3fULL; csr[addr] = val & ~0x3fULL;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) { iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
switch(paddr.val) { switch(paddr.val) {
default: { default: {
for(auto offs = 0U; offs < length; ++offs) { for(auto offs = 0U; offs < length; ++offs) {
@ -1092,13 +1095,12 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, unsi
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) { iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
switch(paddr.val) { switch(paddr.val) {
// TODO remove UART, Peripherals should not be part of the ISS
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1113,34 +1115,36 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, uns
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (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) { if(tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)); uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
// in case of 32 bit system, two writes to tohost are needed, only evaluate on the second (high) write if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
if(tohost_upper && (tohost_lower || tohost_lower_written)) {
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
#ifndef WITH_TCC
throw(iss::simulation_stopped(hostvar));
#endif
break; break;
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'"; LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;
to_host_wr_cnt = 0;
} break; } break;
default: default:
break; break;
} }
tohost_lower_written = false;
} else if(tohost_lower) } else if(tohost_lower)
tohost_lower_written = true; to_host_wr_cnt++;
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) { } else 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)); 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; *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
@ -1151,8 +1155,8 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, uns
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) { iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) {
if(addr == cfg.clic_base) { // cliccfg if(addr == cfg.clic_base) { // cliccfg
*data = clic_cfg_reg; *data = clic_cfg_reg;
for(auto i = 1; i < length; ++i) for(auto i = 1; i < length; ++i)
@ -1171,8 +1175,8 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::read_clic(uint64_t addr, unsigne
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) { iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) {
if(addr == cfg.clic_base) { // cliccfg if(addr == cfg.clic_base) { // cliccfg
clic_cfg_reg = (clic_cfg_reg & ~0x1e) | (*data & 0x1e); 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 } else if(addr >= (cfg.clic_base + 0x40) && (addr + length) <= (cfg.clic_base + 0x40 + cfg.clic_num_trigger * 4)) { // clicinttrig
@ -1187,12 +1191,12 @@ iss::status riscv_hart_m_p<BASE, FEAT, LOGCAT>::write_clic(uint64_t addr, unsign
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> inline void riscv_hart_m_p<BASE, FEAT, LOGCAT>::reset(uint64_t address) { template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
BASE::reset(address); BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val; state.mstatus = hart_state_type::mstatus_reset_val;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> void riscv_hart_m_p<BASE, FEAT, LOGCAT>::check_interrupt() { template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
// TODO: Implement CLIC functionality // TODO: Implement CLIC functionality
// auto ideleg = csr[mideleg]; // auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are // Multiple simultaneous interrupts and traps at the same privilege level are
@ -1215,8 +1219,7 @@ template <typename BASE, features_e FEAT, typename LOGCAT> void riscv_hart_m_p<B
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> 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) {
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] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
auto const trap_id = bit_sub<0, 16>(flags); auto const trap_id = bit_sub<0, 16>(flags);
@ -1237,10 +1240,10 @@ uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_t
*/ */
switch(cause) { switch(cause) {
case 0: case 0:
csr[mtval] = static_cast<reg_t>(tval); csr[mtval] = static_cast<reg_t>(addr);
break; break;
case 2: case 2:
csr[mtval] = (!has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff; csr[mtval] = (!has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff;
break; break;
case 3: case 3:
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) { if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
@ -1250,31 +1253,6 @@ uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_t
} else { } else {
csr[mtval] = addr; 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; break;
case 4: case 4:
case 6: case 6:
@ -1325,18 +1303,18 @@ uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_t
sprintf(buffer.data(), "0x%016lx", addr); sprintf(buffer.data(), "0x%016lx", addr);
#endif #endif
if((flags & 0xffffffff) != 0xffffffff) if((flags & 0xffffffff) != 0xffffffff)
NSCLOG(INFO, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' ("
<< cause << ")" << cause << ")"
<< " at address " << buffer.data() << " occurred"; << " at address " << buffer.data() << " occurred";
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> uint64_t riscv_hart_m_p<BASE, FEAT, LOGCAT>::leave_trap(uint64_t flags) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::leave_trap(uint64_t flags) {
state.mstatus.MIE = state.mstatus.MPIE; state.mstatus.MIE = state.mstatus.MPIE;
state.mstatus.MPIE = 1; state.mstatus.MPIE = 1;
// sets the pc to the value stored in the x epc register. // sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[mepc] & get_pc_mask(); this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
NSCLOG(INFO, LOGCAT) << "Executing xRET"; CLOG(INFO, disass) << "Executing xRET";
check_interrupt(); check_interrupt();
this->reg.trap_state = this->reg.pending_trap; this->reg.trap_state = this->reg.pending_trap;
return this->reg.NEXT_PC; return this->reg.NEXT_PC;

View File

@ -39,9 +39,7 @@
#include "iss/instrumentation_if.h" #include "iss/instrumentation_if.h"
#include "iss/log_categories.h" #include "iss/log_categories.h"
#include "iss/vm_if.h" #include "iss/vm_if.h"
#include "iss/vm_types.h"
#include "riscv_hart_common.h" #include "riscv_hart_common.h"
#include <stdexcept>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -57,12 +55,18 @@
#include <util/ities.h> #include <util/ities.h>
#include <util/sparse_array.h> #include <util/sparse_array.h>
#include <iss/semihosting/semihosting.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 iss {
namespace arch { namespace arch {
template <typename BASE> class riscv_hart_msu_vp : public BASE, public riscv_hart_common { template <typename BASE> class riscv_hart_msu_vp : public BASE {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -328,7 +332,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, 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.cycle + cycle_offset); this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
@ -337,8 +341,6 @@ public:
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } 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: protected:
struct riscv_instrumentation_if : public iss::instrumentation_if { struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -361,7 +363,7 @@ protected:
uint64_t get_pendig_traps() override { return arch.reg.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
@ -371,8 +373,6 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } 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; riscv_hart_msu_vp<BASE>& arch;
}; };
@ -393,11 +393,11 @@ protected:
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
std::array<vm_info, 2> vm; std::array<vm_info, 2> vm;
bool tohost_lower_written = false; uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
unsigned to_host_wr_cnt = 0;
riscv_instrumentation_if instr_if; 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 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_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
using csr_page_type = typename csr_type::page_type; using csr_page_type = typename csr_type::page_type;
@ -555,14 +555,70 @@ 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) { template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) {
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, FILE* fp = fopen(name.c_str(), "r");
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { if(fp) {
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size, std::array<char, 5> buf;
data); auto n = fread(buf.data(), 1, 4, fp);
})) { fclose(fp);
return std::make_pair(entry_address, true); 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();
} }
return std::make_pair(entry_address, false); }
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));
} }
template <typename BASE> template <typename BASE>
@ -570,11 +626,11 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH) { } else if(access && iss::access_type::FETCH) {
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -612,10 +668,8 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
} }
return res; return res;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} break; } break;
@ -653,10 +707,8 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
@ -668,23 +720,23 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -729,7 +781,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// CPPLOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send // LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'"; // '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
@ -786,10 +838,8 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
@ -836,7 +886,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) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t& val) {
auto cycle_val = this->reg.cycle + cycle_offset; auto cycle_val = this->reg.icount + cycle_offset;
if(addr == mcycle) { if(addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if(addr == mcycleh) { } else if(addr == mcycleh) {
@ -857,7 +907,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); mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around cycle_offset = mcycle_csr - this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
@ -885,7 +935,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) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t& val) {
uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if(addr == time) { if(addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if(addr == timeh) { } else if(addr == timeh) {
@ -1027,7 +1077,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_add
switch(paddr.val) { switch(paddr.val) {
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1042,37 +1092,34 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_add
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (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) { if(tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)); uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
// in case of 32 bit system, two writes to tohost are needed, only evaluate on the second (high) write if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
if(tohost_upper && (tohost_lower || tohost_lower_written)) {
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
#ifndef WITH_TCC
throw(iss::simulation_stopped(hostvar));
#endif
break; break;
// throw(iss::simulation_stopped(hostvar));
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'"; LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;
to_host_wr_cnt = 0;
} break; } break;
default: default:
break; break;
} }
tohost_lower_written = false;
} else if(tohost_lower) } else if(tohost_lower)
tohost_lower_written = true; to_host_wr_cnt++;
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) { } else 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)); 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; *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
@ -1257,31 +1304,6 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
// csr[dpc] = addr; // csr[dpc] = addr;
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi) // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
csr[utval | (new_priv << 8)] = addr; 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; break;
case 4: case 4:
case 6: case 6:
@ -1299,7 +1321,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
this->reg.pending_trap = 0; this->reg.pending_trap = 0;
} }
size_t adr = ucause | (new_priv << 8); size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << (traits<BASE>::XLEN - 1)) + cause; csr[adr] = (trap_id << 31) + cause;
// update mstatus // update mstatus
// xPP field of mstatus is written with the active privilege mode at the time // xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus // of the trap; the x PIE field of mstatus

View File

@ -39,9 +39,7 @@
#include "iss/instrumentation_if.h" #include "iss/instrumentation_if.h"
#include "iss/log_categories.h" #include "iss/log_categories.h"
#include "iss/vm_if.h" #include "iss/vm_if.h"
#include "iss/vm_types.h"
#include "riscv_hart_common.h" #include "riscv_hart_common.h"
#include <stdexcept>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -57,13 +55,18 @@
#include <util/ities.h> #include <util/ities.h>
#include <util/sparse_array.h> #include <util/sparse_array.h>
#include <iss/semihosting/semihosting.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 iss {
namespace arch { namespace arch {
template <typename BASE, features_e FEAT = FEAT_NONE, typename LOGCAT = logging::disass> template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_mu_p : public BASE {
class riscv_hart_mu_p : public BASE, public riscv_hart_common {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -90,7 +93,7 @@ protected:
public: public:
using core = BASE; using core = BASE;
using this_class = riscv_hart_mu_p<BASE, FEAT, LOGCAT>; using this_class = riscv_hart_mu_p<BASE, FEAT>;
using phys_addr_t = typename core::phys_addr_t; using phys_addr_t = typename core::phys_addr_t;
using reg_t = typename core::reg_t; using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t; using addr_t = typename core::addr_t;
@ -304,8 +307,8 @@ public:
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, 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.cycle + cycle_offset); this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; }
@ -314,12 +317,10 @@ public:
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } 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: protected:
struct riscv_instrumentation_if : public iss::instrumentation_if { struct riscv_instrumentation_if : public iss::instrumentation_if {
riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch) riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT>& arch)
: arch(arch) {} : arch(arch) {}
/** /**
* get the name of this architecture * get the name of this architecture
@ -338,7 +339,7 @@ protected:
uint64_t get_pendig_traps() override { return arch.reg.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
@ -348,9 +349,7 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } 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_mu_p<BASE, FEAT>& arch;
riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch;
}; };
friend struct riscv_instrumentation_if; friend struct riscv_instrumentation_if;
@ -370,11 +369,11 @@ protected:
int64_t instret_offset{0}; int64_t instret_offset{0};
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
bool tohost_lower_written = false; uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
unsigned to_host_wr_cnt = 0;
riscv_instrumentation_if instr_if; riscv_instrumentation_if instr_if;
semihosting_cb_t<reg_t> semihosting_cb;
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>; 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_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
using csr_page_type = typename csr_type::page_type; using csr_page_type = typename csr_type::page_type;
@ -402,8 +401,8 @@ protected:
std::vector<uint8_t> tcm; std::vector<uint8_t> tcm;
iss::status read_plain(unsigned addr, reg_t& val); iss::status read_csr_reg(unsigned addr, reg_t& val);
iss::status write_plain(unsigned addr, reg_t val); iss::status write_csr_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t& val); iss::status read_null(unsigned addr, reg_t& val);
iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; }
iss::status read_cycle(unsigned addr, reg_t& val); iss::status read_cycle(unsigned addr, reg_t& val);
@ -426,17 +425,15 @@ protected:
iss::status read_intstatus(unsigned addr, reg_t& val); iss::status read_intstatus(unsigned addr, reg_t& val);
iss::status write_intthresh(unsigned addr, reg_t val); iss::status write_intthresh(unsigned addr, reg_t val);
iss::status write_xtvt(unsigned addr, reg_t val); iss::status write_xtvt(unsigned addr, reg_t val);
iss::status write_dcsr(unsigned addr, reg_t val); iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
iss::status read_debug(unsigned addr, reg_t& val); iss::status read_dcsr_reg(unsigned addr, reg_t& val);
iss::status write_dscratch(unsigned addr, reg_t val); iss::status write_dcsr_reg(unsigned addr, reg_t val);
iss::status read_dpc(unsigned addr, reg_t& val); iss::status read_dpc_reg(unsigned addr, reg_t& val);
iss::status write_dpc(unsigned addr, reg_t val); iss::status write_dpc_reg(unsigned addr, reg_t val);
iss::status read_fcsr(unsigned addr, reg_t& val); iss::status write_pmpcfg_reg(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(unsigned addr, reg_t& val) { return iss::status::Err; }; virtual iss::status read_custom_csr_reg(unsigned addr, reg_t& val) { return iss::status::Err; };
virtual iss::status write_custom_csr(unsigned addr, reg_t val) { return iss::status::Err; }; virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) { return iss::status::Err; };
void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr_reg; } void register_custom_csr_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_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr_reg; }
@ -464,8 +461,8 @@ protected:
std::function<mem_write_f> hart_mem_wr_delegate; std::function<mem_write_f> hart_mem_wr_delegate;
}; };
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg) riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
: state() : state()
, instr_if(*this) , instr_if(*this)
, cfg(cfg) { , cfg(cfg) {
@ -476,22 +473,18 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
csr[mimpid] = 1; csr[mimpid] = 1;
uart_buf.str(""); 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) { for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
if(traits<BASE>::XLEN == 32) if(traits<BASE>::XLEN == 32)
for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
@ -499,11 +492,12 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
if(traits<BASE>::XLEN == 32) if(traits<BASE>::XLEN == 32)
for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) { for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) {
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
// csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// common regs // common regs
const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}}; const std::array<unsigned, 4> roaddrs{{misa, mvendorid, marchid, mimpid}};
for(auto addr : roaddrs) { for(auto addr : roaddrs) {
csr_rd_cb[addr] = &this_class::read_plain; csr_rd_cb[addr] = &this_class::read_csr_reg;
csr_wr_cb[addr] = &this_class::write_null; csr_wr_cb[addr] = &this_class::write_null;
} }
const std::array<unsigned, 8> rwaddrs{{ const std::array<unsigned, 8> rwaddrs{{
@ -517,8 +511,8 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
utval, utval,
}}; }};
for(auto addr : rwaddrs) { for(auto addr : rwaddrs) {
csr_rd_cb[addr] = &this_class::read_plain; csr_rd_cb[addr] = &this_class::read_csr_reg;
csr_wr_cb[addr] = &this_class::write_plain; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// special handling & overrides // special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
@ -563,18 +557,18 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
if(FEAT & FEAT_PMP) { if(FEAT & FEAT_PMP) {
for(size_t i = pmpaddr0; i <= pmpaddr15; ++i) { for(size_t i = pmpaddr0; i <= pmpaddr15; ++i) {
csr_rd_cb[i] = &this_class::read_plain; csr_rd_cb[i] = &this_class::read_csr_reg;
csr_wr_cb[i] = &this_class::write_plain; csr_wr_cb[i] = &this_class::write_csr_reg;
} }
for(size_t i = pmpcfg0; i < pmpcfg0 + 16 / sizeof(reg_t); ++i) { for(size_t i = pmpcfg0; i < pmpcfg0 + 16 / sizeof(reg_t); ++i) {
csr_rd_cb[i] = &this_class::read_plain; csr_rd_cb[i] = &this_class::read_csr_reg;
csr_wr_cb[i] = &this_class::write_pmpcfg; csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
} }
} }
if(FEAT & FEAT_EXT_N) { if(FEAT & FEAT_EXT_N) {
csr_rd_cb[mideleg] = &this_class::read_plain; csr_rd_cb[mideleg] = &this_class::read_csr_reg;
csr_wr_cb[mideleg] = &this_class::write_ideleg; csr_wr_cb[mideleg] = &this_class::write_ideleg;
csr_rd_cb[medeleg] = &this_class::read_plain; csr_rd_cb[medeleg] = &this_class::read_csr_reg;
csr_wr_cb[medeleg] = &this_class::write_edeleg; csr_wr_cb[medeleg] = &this_class::write_edeleg;
csr_rd_cb[uie] = &this_class::read_ie; csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie; csr_wr_cb[uie] = &this_class::write_ie;
@ -588,7 +582,7 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
csr_rd_cb[utvec] = &this_class::read_tvec; csr_rd_cb[utvec] = &this_class::read_tvec;
} }
if(FEAT & FEAT_CLIC) { if(FEAT & FEAT_CLIC) {
csr_rd_cb[mtvt] = &this_class::read_plain; csr_rd_cb[mtvt] = &this_class::read_csr_reg;
csr_wr_cb[mtvt] = &this_class::write_xtvt; csr_wr_cb[mtvt] = &this_class::write_xtvt;
// csr_rd_cb[mxnti] = &this_class::read_csr_reg; // csr_rd_cb[mxnti] = &this_class::read_csr_reg;
// csr_wr_cb[mxnti] = &this_class::write_csr_reg; // csr_wr_cb[mxnti] = &this_class::write_csr_reg;
@ -598,14 +592,14 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
// csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg; // csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
// csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg; // csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
// csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg; // csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
csr_rd_cb[mintthresh] = &this_class::read_plain; csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
csr_wr_cb[mintthresh] = &this_class::write_intthresh; csr_wr_cb[mintthresh] = &this_class::write_intthresh;
if(FEAT & FEAT_EXT_N) { if(FEAT & FEAT_EXT_N) {
csr_rd_cb[utvt] = &this_class::read_plain; csr_rd_cb[utvt] = &this_class::read_csr_reg;
csr_wr_cb[utvt] = &this_class::write_xtvt; csr_wr_cb[utvt] = &this_class::write_xtvt;
csr_rd_cb[uintstatus] = &this_class::read_intstatus; csr_rd_cb[uintstatus] = &this_class::read_intstatus;
csr_wr_cb[uintstatus] = &this_class::write_null; csr_wr_cb[uintstatus] = &this_class::write_null;
csr_rd_cb[uintthresh] = &this_class::read_plain; csr_rd_cb[uintthresh] = &this_class::read_csr_reg;
csr_wr_cb[uintthresh] = &this_class::write_intthresh; csr_wr_cb[uintthresh] = &this_class::write_intthresh;
} }
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0}); clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0});
@ -634,33 +628,88 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb); insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
} }
if(FEAT & FEAT_DEBUG) { if(FEAT & FEAT_DEBUG) {
csr_wr_cb[dscratch0] = &this_class::write_dscratch; csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
csr_rd_cb[dscratch0] = &this_class::read_debug; csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
csr_wr_cb[dscratch1] = &this_class::write_dscratch; csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
csr_rd_cb[dscratch1] = &this_class::read_debug; csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
csr_wr_cb[dpc] = &this_class::write_dpc; csr_wr_cb[dpc] = &this_class::write_dpc_reg;
csr_rd_cb[dpc] = &this_class::read_dpc; csr_rd_cb[dpc] = &this_class::read_dpc_reg;
csr_wr_cb[dcsr] = &this_class::write_dcsr; csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
csr_rd_cb[dcsr] = &this_class::read_debug; csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
} }
hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return this->read_mem(a, l, d); }; hart_mem_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); }; 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, typename LOGCAT> template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) { FILE* fp = fopen(name.c_str(), "r");
if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, if(fp) {
[this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { std::array<char, 5> buf;
return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, addr, size, auto n = fread(buf.data(), 1, 4, fp);
data); fclose(fp);
})) { if(n != 4)
return std::make_pair(entry_address, true); 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();
} }
return std::make_pair(entry_address, false); }
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));
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
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, inline void riscv_hart_mu_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
std::function<mem_write_f> wr_fn) { std::function<mem_write_f> wr_fn) {
std::tuple<uint64_t, uint64_t> entry{base, size}; std::tuple<uint64_t, uint64_t> entry{base, size};
auto it = std::upper_bound( auto it = std::upper_bound(
@ -672,14 +721,13 @@ inline void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::insert_mem_range(uint64_t base,
memfn_write.insert(std::begin(memfn_write) + idx, wr_fn); memfn_write.insert(std::begin(memfn_write) + idx, wr_fn);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
inline iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_pmpcfg(unsigned addr, reg_t val) {
csr[addr] = val & 0x9f9f9f9f; csr[addr] = val & 0x9f9f9f9f;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
bool riscv_hart_mu_p<BASE, FEAT, LOGCAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) { bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
constexpr auto PMP_SHIFT = 2U; constexpr auto PMP_SHIFT = 2U;
constexpr auto PMP_R = 0x1U; constexpr auto PMP_R = 0x1U;
constexpr auto PMP_W = 0x2U; constexpr auto PMP_W = 0x2U;
@ -759,16 +807,16 @@ bool riscv_hart_mu_p<BASE, FEAT, LOGCAT>::pmp_check(const access_type type, cons
return !any_active || this->reg.PRIV == PRIV_M; return !any_active || this->reg.PRIV == PRIV_M;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read(const address_type type, const access_type access, const uint32_t space, 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 uint64_t addr, const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(is_fetch(access)) { } else if(is_fetch(access)) {
CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -818,10 +866,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read(const address_type type, c
} }
return res; return res;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} break; } break;
@ -848,38 +894,36 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read(const address_type type, c
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write(const address_type type, const access_type access, const uint32_t space, 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 uint64_t addr, const unsigned length, const uint8_t* const data) { const unsigned length, const uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -940,6 +984,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write(const address_type type,
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
} }
@ -990,16 +1036,13 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write(const address_type type,
} }
return iss::Ok; return iss::Ok;
} catch(trap_access& ta) { } catch(trap_access& ta) {
if((access & access_type::DEBUG) == 0) {
this->reg.trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data = ta.addr; fault_data = ta.addr;
}
return iss::Err; return iss::Err;
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_csr(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t& val) {
if(addr >= csr.size()) if(addr >= csr.size())
return iss::Err; return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
@ -1011,8 +1054,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_csr(unsigned addr, reg_t&
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t val) {
if(addr >= csr.size()) if(addr >= csr.size())
return iss::Err; return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
@ -1026,27 +1068,23 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_csr(unsigned addr, reg_t
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t& val) {
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, typename LOGCAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_plain(unsigned addr, reg_t& val) {
val = csr[addr]; val = csr[addr];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_null(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_plain(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) {
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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) { if(addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if(addr == mcycleh) { } else if(addr == mcycleh) {
@ -1055,8 +1093,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_cycle(unsigned addr, reg_t
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_t val) {
if(sizeof(typename traits<BASE>::reg_t) != 4) { if(sizeof(typename traits<BASE>::reg_t) != 4) {
mcycle_csr = static_cast<uint64_t>(val); mcycle_csr = static_cast<uint64_t>(val);
} else { } else {
@ -1066,12 +1103,11 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_cycle(unsigned addr, reg_
mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff); mcycle_csr = (static_cast<uint64_t>(val) << 32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around cycle_offset = mcycle_csr - this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg_t& val) {
if((addr & 0xff) == (minstret & 0xff)) { if((addr & 0xff) == (minstret & 0xff)) {
val = static_cast<reg_t>(this->reg.instret); val = static_cast<reg_t>(this->reg.instret);
} else if((addr & 0xff) == (minstreth & 0xff)) { } else if((addr & 0xff) == (minstreth & 0xff)) {
@ -1080,8 +1116,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_instret(unsigned addr, reg
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, reg_t val) {
if(sizeof(typename traits<BASE>::reg_t) != 4) { if(sizeof(typename traits<BASE>::reg_t) != 4) {
this->reg.instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
@ -1095,9 +1130,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_instret(unsigned addr, re
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::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) { if(addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if(addr == timeh) { } else if(addr == timeh) {
@ -1108,27 +1142,22 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_time(unsigned addr, reg_t&
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t& val) {
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; val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2;
return iss::Ok; 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); val = state.mstatus & hart_state_type::get_mask((addr >> 8) & 0x3);
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_status(unsigned addr, reg_t val) {
state.write_mstatus(val, (addr >> 8) & 0x3); state.write_mstatus(val, (addr >> 8) & 0x3);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cause(unsigned addr, reg_t& val) {
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) { 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 = csr[addr] & ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
auto mode = (addr >> 8) & 0x3; auto mode = (addr >> 8) & 0x3;
@ -1148,8 +1177,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_cause(unsigned addr, reg_t
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
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) { if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) {
auto mask = ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); auto mask = ((1UL << (traits<BASE>::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16));
csr[addr] = (val & mask) | (csr[addr] & ~mask); csr[addr] = (val & mask) | (csr[addr] & ~mask);
@ -1172,14 +1200,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_cause(unsigned addr, reg_
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_hartid(unsigned addr, reg_t& val) {
val = mhartid_reg; val = mhartid_reg;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ie(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ie(unsigned addr, reg_t& val) {
auto mask = get_irq_mask((addr >> 8) & 0x3); auto mask = get_irq_mask((addr >> 8) & 0x3);
val = csr[mie] & mask; val = csr[mie] & mask;
if(this->reg.PRIV != 3) if(this->reg.PRIV != 3)
@ -1187,16 +1213,14 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ie(unsigned addr, reg_t& v
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_ie(unsigned addr, reg_t val) {
auto mask = get_irq_mask((addr >> 8) & 0x3); auto mask = get_irq_mask((addr >> 8) & 0x3);
csr[mie] = (csr[mie] & ~mask) | (val & mask); csr[mie] = (csr[mie] & ~mask) | (val & mask);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ip(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ip(unsigned addr, reg_t& val) {
auto mask = get_irq_mask((addr >> 8) & 0x3); auto mask = get_irq_mask((addr >> 8) & 0x3);
val = csr[mip] & mask; val = csr[mip] & mask;
if(this->reg.PRIV != 3) if(this->reg.PRIV != 3)
@ -1204,28 +1228,24 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_ip(unsigned addr, reg_t& v
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ideleg(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_ideleg(unsigned addr, reg_t val) {
auto mask = 0b000100010001; // only U mode supported auto mask = 0b000100010001; // only U mode supported
csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask); csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask);
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_edeleg(unsigned addr, reg_t val) {
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 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); csr[medeleg] = (csr[medeleg] & ~mask) | (val & mask);
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask(); csr[addr] = val & get_pc_mask();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dcsr_dcsr(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
// +-------------- ebreakm // +-------------- ebreakm
@ -1236,40 +1256,35 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dcsr(unsigned addr, reg_t
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_debug(unsigned addr, reg_t& val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
val = csr[addr]; val = csr[addr];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dscratch(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_dpc(unsigned addr, reg_t& val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
val = this->reg.DPC; val = this->reg.DPC;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_dpc(unsigned addr, reg_t val) {
if(!debug_mode_active()) if(!debug_mode_active())
throw illegal_instruction_fault(this->fault_data); throw illegal_instruction_fault(this->fault_data);
this->reg.DPC = val; this->reg.DPC = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_intstatus(unsigned addr, reg_t& val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_intstatus(unsigned addr, reg_t& val) {
auto mode = (addr >> 8) & 0x3; auto mode = (addr >> 8) & 0x3;
val = clic_uact_lvl & 0xff; val = clic_uact_lvl & 0xff;
if(mode == 0x3) if(mode == 0x3)
@ -1277,32 +1292,18 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_intstatus(unsigned addr, r
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
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; csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_xtvt(unsigned addr, reg_t val) {
csr[addr] = val & ~0x3fULL; csr[addr] = val & ~0x3fULL;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) {
switch(paddr.val) { switch(paddr.val) {
default: { default: {
for(auto offs = 0U; offs < length; ++offs) { for(auto offs = 0U; offs < length; ++offs) {
@ -1313,13 +1314,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_mem(phys_addr_t paddr, uns
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
switch(paddr.val) { switch(paddr.val) {
// TODO remove UART, Peripherals should not be part of the ISS
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1334,37 +1334,34 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, un
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (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) { if(tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)); uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
// in case of 32 bit system, two writes to tohost are needed, only evaluate on the second (high) write if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
if(tohost_upper && (tohost_lower || tohost_lower_written)) {
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
#ifndef WITH_TCC
throw(iss::simulation_stopped(hostvar));
#endif
break; break;
// throw(iss::simulation_stopped(hostvar));
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'"; LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;
to_host_wr_cnt = 0;
} break; } break;
default: default:
break; break;
} }
tohost_lower_written = false;
} else if(tohost_lower) } else if(tohost_lower)
tohost_lower_written = true; to_host_wr_cnt++;
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) { } else 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)); 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; *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
@ -1375,8 +1372,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_mem(phys_addr_t paddr, un
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t* const data) {
if(addr == cfg.clic_base) { // cliccfg if(addr == cfg.clic_base) { // cliccfg
*data = clic_cfg_reg; *data = clic_cfg_reg;
for(auto i = 1; i < length; ++i) for(auto i = 1; i < length; ++i)
@ -1395,8 +1392,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::read_clic(uint64_t addr, unsign
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t* const data) {
if(addr == cfg.clic_base) { // cliccfg if(addr == cfg.clic_base) { // cliccfg
clic_cfg_reg = (clic_cfg_reg & ~0x1e) | (*data & 0x1e); 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 } else if(addr >= (cfg.clic_base + 0x40) && (addr + length) <= (cfg.clic_base + 0x40 + cfg.clic_num_trigger * 4)) { // clicinttrig
@ -1411,12 +1408,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT, LOGCAT>::write_clic(uint64_t addr, unsig
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> inline void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::reset(uint64_t address) { template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT>::reset(uint64_t address) {
BASE::reset(address); BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val; state.mstatus = hart_state_type::mstatus_reset_val;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> void riscv_hart_mu_p<BASE, FEAT, LOGCAT>::check_interrupt() { template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::check_interrupt() {
// TODO: Implement CLIC functionality // TODO: Implement CLIC functionality
auto ideleg = csr[mideleg]; auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are // Multiple simultaneous interrupts and traps at the same privilege level are
@ -1439,8 +1436,7 @@ template <typename BASE, features_e FEAT, typename LOGCAT> void riscv_hart_mu_p<
} }
} }
template <typename BASE, features_e FEAT, typename LOGCAT> 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) {
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] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
if(flags == std::numeric_limits<uint64_t>::max()) if(flags == std::numeric_limits<uint64_t>::max())
@ -1478,31 +1474,6 @@ uint64_t riscv_hart_mu_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_
} else { } else {
csr[utval | (new_priv << 8)] = addr; 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; break;
case 4: case 4:
case 6: case 6:
@ -1574,7 +1545,7 @@ uint64_t riscv_hart_mu_p<BASE, FEAT, LOGCAT>::enter_trap(uint64_t flags, uint64_
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
template <typename BASE, features_e FEAT, typename LOGCAT> uint64_t riscv_hart_mu_p<BASE, FEAT, LOGCAT>::leave_trap(uint64_t flags) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
auto cur_priv = this->reg.PRIV; auto cur_priv = this->reg.PRIV;
auto inst_priv = (flags & 0x3) ? 3 : 0; auto inst_priv = (flags & 0x3) ? 3 : 0;
if(inst_priv > cur_priv) { if(inst_priv > cur_priv) {

View File

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2024 MINRES Technologies GmbH * Copyright (C) 2017 - 2020 MINRES Technologies GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

File diff suppressed because one or more lines are too long

View File

@ -87,7 +87,7 @@ public:
virtual ~wt_cache() = default; virtual ~wt_cache() = default;
unsigned size{4096}; unsigned size{4096};
unsigned line_sz{64}; unsigned line_sz{32};
unsigned ways{1}; unsigned ways{1};
uint64_t io_address{0xf0000000}; uint64_t io_address{0xf0000000};
uint64_t io_addr_mask{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)); icache_ptr.reset(new cache::cache(size, line_sz, ways));
dcache_ptr.reset(new cache::cache(size, line_sz, ways)); dcache_ptr.reset(new cache::cache(size, line_sz, ways));
} }
if((a.access & iss::access_type::FETCH) == iss::access_type::FETCH || (a.val & io_addr_mask) != io_address) { if((a.val & io_addr_mask) != io_address) {
auto set_addr = (a.val & (size - 1)) >> util::ilog2(line_sz * ways); auto set_addr = (a.val & (size - 1)) >> util::ilog2(line_sz * ways);
auto tag_addr = a.val >> util::ilog2(line_sz); auto tag_addr = a.val >> util::ilog2(line_sz);
auto& set = (is_fetch(a.access) ? icache_ptr : dcache_ptr)->sets[set_addr]; auto& set = (is_fetch(a.access) ? icache_ptr : dcache_ptr)->sets[set_addr];

File diff suppressed because it is too large Load Diff

View File

@ -30,8 +30,8 @@
* *
*******************************************************************************/ *******************************************************************************/
#ifndef _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_ #ifndef _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_
#define _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_ #define _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_
#include "iss/arch_if.h" #include "iss/arch_if.h"
#include <iss/arch/traits.h> #include <iss/arch/traits.h>
@ -48,10 +48,6 @@
namespace iss { namespace iss {
namespace debugger { namespace debugger {
char const* const get_csr_name(unsigned);
constexpr auto csr_offset = 100U;
using namespace iss::arch; using namespace iss::arch;
using namespace iss::debugger; using namespace iss::debugger;
@ -133,17 +129,11 @@ public:
protected: protected:
static inline constexpr addr_t map_addr(const addr_t& i) { return i; } static inline constexpr addr_t map_addr(const addr_t& i) { return i; }
std::string csr_xml;
iss::arch_if* core; iss::arch_if* core;
rp_thread_ref thread_idx; 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) { template <typename ARCH> status riscv_target_adapter<ARCH>::set_gen_thread(rp_thread_ref& thread) {
thread_idx = thread; thread_idx = thread;
return Ok; return Ok;
@ -184,30 +174,13 @@ 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) { template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) {
CPPLOG(TRACE) << "reading target registers"; LOG(TRACE) << "reading target registers";
// return idx<0?:;
data.clear(); data.clear();
avail.clear(); avail.clear();
const uint8_t* reg_base = core->get_regs_base_ptr(); const uint8_t* reg_base = core->get_regs_base_ptr();
auto start_reg = arch::traits<ARCH>::X0; auto start_reg = arch::traits<ARCH>::X0;
for(size_t i = 0; i < 33; ++i) { for(size_t reg_no = start_reg; reg_no < start_reg + 33 /*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
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; auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no]; unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
for(size_t j = 0; j < reg_width; ++j) { for(size_t j = 0; j < reg_width; ++j) {
@ -215,7 +188,21 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::
avail.push_back(0xff); 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; return Ok;
} }
@ -223,25 +210,25 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
auto start_reg = arch::traits<ARCH>::X0; auto start_reg = arch::traits<ARCH>::X0;
auto* reg_base = core->get_regs_base_ptr(); auto* reg_base = core->get_regs_base_ptr();
auto iter = data.data(); auto iter = data.data();
auto iter_end = data.data() + data.size(); bool e_ext = arch::traits<ARCH>::PC < 32;
for(size_t i = 0; i < 33 && iter < iter_end; ++i) { for(size_t reg_no = 0; reg_no < start_reg + 33 /*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
auto reg_width = arch::traits<ARCH>::XLEN / 8; if(e_ext && reg_no > 15) {
if(i < arch::traits<ARCH>::RFS) { if(reg_no == 32) {
auto offset = traits<ARCH>::reg_byte_offsets[start_reg + i]; auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
std::copy(iter, iter + reg_width, reg_base + offset);
} else if(i == 32) {
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]; auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
std::copy(iter, iter + reg_width, reg_base + offset); 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);
} }
iter += reg_width; } else {
} auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
if(iss::arch::traits<ARCH>::FLEN > 0) { auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
auto fstart_reg = get_f0_offset<ARCH>(); std::copy(iter, iter + reg_width, reg_base);
auto reg_width = arch::traits<ARCH>::FLEN / 8; iter += 4;
for(size_t i = 0; i < 32 && iter < iter_end; ++i) { reg_base += offset;
unsigned offset = traits<ARCH>::reg_byte_offsets[fstart_reg + i];
std::copy(iter, iter + reg_width, reg_base + offset);
iter += reg_width;
} }
} }
return Ok; return Ok;
@ -249,7 +236,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
template <typename ARCH> 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) { 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 < csr_offset) { if(reg_no < 65) {
// auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename // auto reg_size = arch::traits<ARCH>::reg_bit_width(static_cast<typename
// arch::traits<ARCH>::reg_e>(reg_no))/8; // arch::traits<ARCH>::reg_e>(reg_no))/8;
auto* reg_base = core->get_regs_base_ptr(); auto* reg_base = core->get_regs_base_ptr();
@ -260,24 +247,23 @@ 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::copy(reg_base + offset, reg_base + offset + reg_width, data.begin());
std::fill(avail.begin(), avail.end(), 0xff); std::fill(avail.begin(), avail.end(), 0xff);
} else { } else {
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, reg_no - csr_offset); typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, reg_no - 65);
data.resize(sizeof(typename traits<ARCH>::reg_t)); data.resize(sizeof(typename traits<ARCH>::reg_t));
avail.resize(sizeof(typename traits<ARCH>::reg_t)); avail.resize(sizeof(typename traits<ARCH>::reg_t));
std::fill(avail.begin(), avail.end(), 0xff); std::fill(avail.begin(), avail.end(), 0xff);
core->read(a, data.size(), data.data()); core->read(a, data.size(), data.data());
std::fill(avail.begin(), avail.end(), 0xff);
} }
return data.size() > 0 ? Ok : Err; 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) { template <typename ARCH> status riscv_target_adapter<ARCH>::write_single_register(unsigned int reg_no, const std::vector<uint8_t>& data) {
if(reg_no < csr_offset) { if(reg_no < 65) {
auto* reg_base = core->get_regs_base_ptr(); 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 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]; auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset); std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
} else { } else {
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - csr_offset); typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - 65);
core->write(a, data.size(), data.data()); core->write(a, data.size(), data.data());
} }
return Ok; return Ok;
@ -290,7 +276,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) { 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_WRITE, iss::address_type::VIRTUAL, 0, addr}); auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
auto f = [&]() -> status { return core->write(a, data.size(), data.data()); }; auto f = [&]() -> status { return core->write(a, data.size(), data.data()); };
return srv->execute_syncronized(f); return srv->execute_syncronized(f);
} }
@ -342,9 +328,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 saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length}); auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val); target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
CPPLOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val
<< std::dec; << std::dec;
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok; return Ok;
} }
} }
@ -359,13 +345,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}); auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val); unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
if(handle) { if(handle) {
CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec; LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec;
// TODO: check length of addr range // TODO: check length of addr range
target_adapter_base::bp_lut.removeEntry(handle); target_adapter_base::bp_lut.removeEntry(handle);
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok; return Ok;
} }
CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Err; return Err;
} }
} }
@ -383,57 +369,93 @@ 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) { template <typename ARCH> status riscv_target_adapter<ARCH>::target_xml_query(std::string& out_buf) {
if(!csr_xml.size()) { const std::string res{"<?xml version=\"1.0\"?><!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
std::ostringstream oss; "<target><architecture>riscv:rv32</architecture>"
oss << "<?xml version=\"1.0\"?><!DOCTYPE feature SYSTEM \"gdb-target.dtd\"><target version=\"1.0\">\n"; //" <feature name=\"org.gnu.gdb.riscv.rv32i\">\n"
if(iss::arch::traits<ARCH>::XLEN == 32) //" <reg name=\"x0\" bitsize=\"32\" group=\"general\"/>\n"
oss << "<architecture>riscv:rv32</architecture>\n"; //" <reg name=\"x1\" bitsize=\"32\" group=\"general\"/>\n"
else if(iss::arch::traits<ARCH>::XLEN == 64) //" <reg name=\"x2\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <architectureriscv:rv64</architecture>\n"; //" <reg name=\"x3\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <feature name=\"org.gnu.gdb.riscv.cpu\">\n"; //" <reg name=\"x4\" bitsize=\"32\" group=\"general\"/>\n"
auto reg_base_num = iss::arch::traits<ARCH>::X0; //" <reg name=\"x5\" bitsize=\"32\" group=\"general\"/>\n"
for(auto i = 0U; i < iss::arch::traits<ARCH>::RFS; ++i) { //" <reg name=\"x6\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"x" << i << "\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[reg_base_num + i] //" <reg name=\"x7\" bitsize=\"32\" group=\"general\"/>\n"
<< "\" type=\"int\" regnum=\"" << i << "\"/>\n"; //" <reg name=\"x8\" bitsize=\"32\" group=\"general\"/>\n"
} //" <reg name=\"x9\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"pc\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[iss::arch::traits<ARCH>::PC] //" <reg name=\"x10\" bitsize=\"32\" group=\"general\"/>\n"
<< "\" type=\"code_ptr\" regnum=\"" << 32U << "\"/>\n"; //" <reg name=\"x11\" bitsize=\"32\" group=\"general\"/>\n"
oss << " </feature>\n"; //" <reg name=\"x12\" bitsize=\"32\" group=\"general\"/>\n"
if(iss::arch::traits<ARCH>::FLEN > 0) { //" <reg name=\"x13\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <feature name=\"org.gnu.gdb.riscv.fpu\">\n"; //" <reg name=\"x14\" bitsize=\"32\" group=\"general\"/>\n"
auto reg_base_num = get_f0_offset<ARCH>(); //" <reg name=\"x15\" bitsize=\"32\" group=\"general\"/>\n"
auto type = iss::arch::traits<ARCH>::FLEN == 32 ? "ieee_single" : "riscv_double"; //" <reg name=\"x16\" bitsize=\"32\" group=\"general\"/>\n"
for(auto i = 0U; i < 32; ++i) { //" <reg name=\"x17\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"f" << i << "\" bitsize=\"" << iss::arch::traits<ARCH>::reg_bit_widths[reg_base_num + i] //" <reg name=\"x18\" bitsize=\"32\" group=\"general\"/>\n"
<< "\" type=\"" << type << "\" regnum=\"" << i + 33 << "\"/>\n"; //" <reg name=\"x19\" bitsize=\"32\" group=\"general\"/>\n"
} //" <reg name=\"x20\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"fcsr\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"103\" type int/>\n"; //" <reg name=\"x21\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"fflags\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"101\" type int/>\n"; //" <reg name=\"x22\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <reg name=\"frm\" bitsize=\"" << iss::arch::traits<ARCH>::XLEN << "\" regnum=\"102\" type int/>\n"; //" <reg name=\"x23\" bitsize=\"32\" group=\"general\"/>\n"
oss << " </feature>\n"; //" <reg name=\"x24\" bitsize=\"32\" group=\"general\"/>\n"
} //" <reg name=\"x25\" bitsize=\"32\" group=\"general\"/>\n"
oss << " <feature name=\"org.gnu.gdb.riscv.csr\">\n"; //" <reg name=\"x26\" bitsize=\"32\" group=\"general\"/>\n"
std::vector<uint8_t> data; //" <reg name=\"x27\" bitsize=\"32\" group=\"general\"/>\n"
std::vector<uint8_t> avail; //" <reg name=\"x28\" bitsize=\"32\" group=\"general\"/>\n"
data.resize(sizeof(typename traits<ARCH>::reg_t)); //" <reg name=\"x29\" bitsize=\"32\" group=\"general\"/>\n"
avail.resize(sizeof(typename traits<ARCH>::reg_t)); //" <reg name=\"x30\" bitsize=\"32\" group=\"general\"/>\n"
for(auto i = 0U; i < 4096; ++i) { //" <reg name=\"x31\" bitsize=\"32\" group=\"general\"/>\n"
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, i); //" </feature>\n"
std::fill(avail.begin(), avail.end(), 0xff); "</target>"};
auto res = core->read(a, data.size(), data.data()); out_buf = res;
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; 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 debugger
} // namespace iss } // namespace iss
#endif /* _ISS_ARCH_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */ #endif /* _ISS_DEBUGGER_RISCV_TARGET_ADAPTER_H_ */

View File

@ -61,7 +61,7 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
try { try {
auto root = YAML::LoadAll(is); auto root = YAML::LoadAll(is);
if(root.size() != 1) { if(root.size() != 1) {
CPPLOG(ERR) << "Too many root nodes in YAML file " << config_file_name; LOG(ERR) << "Too many root nodes in YAML file " << config_file_name;
} }
for(auto p : root[0]) { for(auto p : root[0]) {
auto isa_subset = p.first; 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) { } catch(YAML::ParserException& e) {
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what(); LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
return false; return false;
} }
} else { } else {
CPPLOG(ERR) << "Could not open input file " << config_file_name; LOG(ERR) << "Could not open input file " << config_file_name;
return false; return false;
} }
} }

View File

@ -47,7 +47,7 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
try { try {
auto root = YAML::LoadAll(is); auto root = YAML::LoadAll(is);
if(root.size() != 1) { if(root.size() != 1) {
CPPLOG(ERR) << "Too many rro nodes in YAML file " << config_file_name; LOG(ERR) << "Too many rro nodes in YAML file " << config_file_name;
} }
for(auto p : root[0]) { for(auto p : root[0]) {
auto isa_subset = p.first; 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()); rep_counts.resize(delays.size());
} catch(YAML::ParserException& e) { } catch(YAML::ParserException& e) {
CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what(); LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
} }
} else { } else {
CPPLOG(ERR) << "Could not open input file " << config_file_name; LOG(ERR) << "Could not open input file " << config_file_name;
} }
} }
} }
@ -81,7 +81,7 @@ iss::plugin::instruction_count::~instruction_count() {
size_t idx = 0; size_t idx = 0;
for(auto it : delays) { for(auto it : delays) {
if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0)) if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0))
CPPLOG(INFO) << it.instr_name << ";" << rep_counts[idx]; LOG(INFO) << it.instr_name << ";" << rep_counts[idx];
idx++; idx++;
} }
} }

View File

@ -1,297 +0,0 @@
#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>;

View File

@ -1,61 +0,0 @@
#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

View File

@ -31,12 +31,8 @@
*******************************************************************************/ *******************************************************************************/
#include <array> #include <array>
#include <cstdint>
#include <iostream> #include <iostream>
#include <iss/factory.h> #include <iss/factory.h>
#include <iss/semihosting/semihosting.h>
#include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "iss/arch/tgc_mapper.h" #include "iss/arch/tgc_mapper.h"
@ -56,6 +52,7 @@
#endif #endif
namespace po = boost::program_options; namespace po = boost::program_options;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
/* /*
* Define and parse the program options * Define and parse the program options
@ -69,14 +66,13 @@ int main(int argc, char* argv[]) {
("logfile,l", po::value<std::string>(), "Sets default log file.") ("logfile,l", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
("ilimit,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate") ("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
("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") ("reset,r", po::value<std::string>(), "reset address")
("dump-ir", "dump the intermediate representation") ("dump-ir", "dump the intermediate representation")
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, llvm, tcc, asmjit") ("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc")
("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list"); ("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
@ -120,8 +116,6 @@ int main(int argc, char* argv[]) {
// instantiate the simulator // instantiate the simulator
iss::vm_ptr vm{nullptr}; iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{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>()); std::string isa_opt(clim["isa"].as<std::string>());
if(isa_opt.size() == 0 || isa_opt == "?") { if(isa_opt.size() == 0 || isa_opt == "?") {
auto list = f.get_names(); auto list = f.get_names();
@ -129,8 +123,7 @@ int main(int argc, char* argv[]) {
std::cout << "Available implementations (core|platform|backend):\n - " << util::join(list, "\n - ") << std::endl; std::cout << "Available implementations (core|platform|backend):\n - " << util::join(list, "\n - ") << std::endl;
return 0; return 0;
} else if(isa_opt.find('|') != std::string::npos) { } else if(isa_opt.find('|') != std::string::npos) {
std::tie(cpu, vm) = std::tie(cpu, vm) = f.create(isa_opt + "|" + clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
f.create(isa_opt + "|" + clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>(), &semihosting_cb);
} else { } else {
auto base_isa = isa_opt.substr(0, 5); auto base_isa = isa_opt.substr(0, 5);
if(base_isa == "tgc5d" || base_isa == "tgc5e") { if(base_isa == "tgc5d" || base_isa == "tgc5e") {
@ -138,17 +131,14 @@ int main(int argc, char* argv[]) {
} else { } else {
isa_opt += "|m_p|" + clim["backend"].as<std::string>(); isa_opt += "|m_p|" + clim["backend"].as<std::string>();
} }
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>(), &semihosting_cb); std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>());
} }
if(!cpu) { if(!cpu) {
auto list = f.get_names(); LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
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; return 127;
} }
if(!vm) { if(!vm) {
CPPLOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl; LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
return 127; return 127;
} }
if(clim.count("plugin")) { if(clim.count("plugin")) {
@ -184,7 +174,7 @@ int main(int argc, char* argv[]) {
} else } else
#endif #endif
{ {
CPPLOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl; LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
return 127; return 127;
} }
} }
@ -208,70 +198,24 @@ int main(int argc, char* argv[]) {
auto start_addr = vm->get_arch()->load_file(input); auto start_addr = vm->get_arch()->load_file(input);
if(start_addr.second) if(start_addr.second)
start_address = start_addr.first; start_address = start_addr.first;
else {
LOG(ERR) << "Error occured while loading file " << input << std::endl;
return 1;
}
} }
for(std::string input : args) { for(std::string input : args) {
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
if(start_addr.second) if(start_addr.second)
start_address = start_addr.first; start_address = start_addr.first;
else {
LOG(ERR) << "Error occured while loading file " << input << std::endl;
return 1;
}
} }
if(clim.count("reset")) { if(clim.count("reset")) {
auto str = clim["reset"].as<std::string>(); 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); start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
} }
vm->reset(start_address); vm->reset(start_address);
auto limit = clim["ilimit"].as<uint64_t>(); auto cycles = clim["instructions"].as<uint64_t>();
auto cond = iss::finish_cond_e::JUMP_TO_SELF; res = vm->start(cycles, dump);
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) { } catch(std::exception& e) {
CPPLOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl; LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl;
res = 2; res = 2;
} }
// cleanup to let plugins report if needed // cleanup to let plugins report of needed
for(auto* p : plugin_list) { for(auto* p : plugin_list) {
delete p; delete p;
} }

View File

@ -42,6 +42,7 @@
#include <iss/plugin/loader.h> #include <iss/plugin/loader.h>
#endif #endif
#include "sc_core_adapter_if.h" #include "sc_core_adapter_if.h"
#include <iss/arch/tgc_mapper.h>
#include <scc/report.h> #include <scc/report.h>
#include <util/ities.h> #include <util/ities.h>
#include <iostream> #include <iostream>
@ -124,7 +125,7 @@ using vm_ptr = std::unique_ptr<iss::vm_if>;
class core_wrapper { class core_wrapper {
public: public:
core_wrapper(core_complex_if* owner) core_wrapper(core_complex* owner)
: owner(owner) {} : owner(owner) {}
void reset(uint64_t addr) { vm->reset(addr); } void reset(uint64_t addr) { vm->reset(addr); }
@ -180,7 +181,7 @@ public:
"SystemC sub-commands: break <time>, print_time"}); "SystemC sub-commands: break <time>, print_time"});
} }
core_complex_if* const owner; core_complex* const owner;
vm_ptr vm{nullptr}; vm_ptr vm{nullptr};
sc_cpu_ptr cpu{nullptr}; sc_cpu_ptr cpu{nullptr};
iss::debugger::target_adapter_if* tgt_adapter{nullptr}; iss::debugger::target_adapter_if* tgt_adapter{nullptr};
@ -196,9 +197,9 @@ struct core_trace {
scv_tr_handle tr_handle; scv_tr_handle tr_handle;
}; };
SC_HAS_PROCESS(core_complex); // NOLINT
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
template <unsigned int BUSWIDTH> core_complex::core_complex(sc_module_name const& name)
core_complex<BUSWIDTH>::core_complex(sc_module_name const& name)
: sc_module(name) : sc_module(name)
, fetch_lut(tlm_dmi_ext()) , fetch_lut(tlm_dmi_ext())
, read_lut(tlm_dmi_ext()) , read_lut(tlm_dmi_ext())
@ -207,7 +208,7 @@ core_complex<BUSWIDTH>::core_complex(sc_module_name const& name)
} }
#endif #endif
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::init() { void core_complex::init() {
trc = new core_trace(); trc = new core_trace();
ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void { ibus.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void {
auto lut_entry = fetch_lut.getEntry(start); auto lut_entry = fetch_lut.getEntry(start);
@ -226,7 +227,6 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::init() {
} }
}); });
SC_HAS_PROCESS(core_complex<BUSWIDTH>); // NOLINT
SC_THREAD(run); SC_THREAD(run);
SC_METHOD(rst_cb); SC_METHOD(rst_cb);
sensitive << rst_i; sensitive << rst_i;
@ -252,16 +252,16 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::init() {
#endif #endif
} }
template <unsigned int BUSWIDTH> core_complex<BUSWIDTH>::~core_complex() { core_complex::~core_complex() {
delete cpu; delete cpu;
delete trc; delete trc;
for(auto* p : plugin_list) for(auto* p : plugin_list)
delete p; delete p;
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::trace(sc_trace_file* trf) const {} void core_complex::trace(sc_trace_file* trf) const {}
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::before_end_of_elaboration() { void core_complex::before_end_of_elaboration() {
SCCDEBUG(SCMOD) << "instantiating iss::arch::tgf with " << GET_PROP_VALUE(backend) << " backend"; SCCDEBUG(SCMOD) << "instantiating iss::arch::tgf with " << GET_PROP_VALUE(backend) << " backend";
// cpu = scc::make_unique<core_wrapper>(this); // cpu = scc::make_unique<core_wrapper>(this);
cpu = new core_wrapper(this); cpu = new core_wrapper(this);
@ -302,7 +302,7 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::before_end_of_elab
} }
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::start_of_simulation() { void core_complex::start_of_simulation() {
// quantum_keeper.reset(); // quantum_keeper.reset();
if(GET_PROP_VALUE(elf_file).size() > 0) { if(GET_PROP_VALUE(elf_file).size() > 0) {
istringstream is(GET_PROP_VALUE(elf_file)); istringstream is(GET_PROP_VALUE(elf_file));
@ -325,7 +325,7 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::start_of_simulatio
} }
} }
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::disass_output(uint64_t pc, const std::string instr_str) { bool core_complex::disass_output(uint64_t pc, const std::string instr_str) {
if(trc->m_db == nullptr) if(trc->m_db == nullptr)
return false; return false;
if(trc->tr_handle.is_active()) if(trc->tr_handle.is_active())
@ -339,7 +339,7 @@ template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::disass_output(uint
return true; return true;
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::forward() { void core_complex::forward() {
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
set_clock_period(clk_i.read()); set_clock_period(clk_i.read());
#else #else
@ -348,24 +348,24 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::forward() {
#endif #endif
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::set_clock_period(sc_core::sc_time period) { void core_complex::set_clock_period(sc_core::sc_time period) {
curr_clk = period; curr_clk = period;
if(period == SC_ZERO_TIME) if(period == SC_ZERO_TIME)
cpu->set_interrupt_execution(true); cpu->set_interrupt_execution(true);
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::rst_cb() { void core_complex::rst_cb() {
if(rst_i.read()) if(rst_i.read())
cpu->set_interrupt_execution(true); cpu->set_interrupt_execution(true);
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::sw_irq_cb() { cpu->local_irq(3, sw_irq_i.read()); } void core_complex::sw_irq_cb() { cpu->local_irq(3, sw_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::timer_irq_cb() { cpu->local_irq(7, timer_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::ext_irq_cb() { cpu->local_irq(11, ext_irq_i.read()); }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::local_irq_cb() { void core_complex::local_irq_cb() {
for(auto i = 0U; i < local_irq_i.size(); ++i) { for(auto i = 0U; i < local_irq_i.size(); ++i) {
if(local_irq_i[i].event()) { if(local_irq_i[i].event()) {
cpu->local_irq(16 + i, local_irq_i[i].read()); cpu->local_irq(16 + i, local_irq_i[i].read());
@ -373,7 +373,7 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::local_irq_cb() {
} }
} }
template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::run() { void core_complex::run() {
wait(SC_ZERO_TIME); // separate from elaboration phase wait(SC_ZERO_TIME); // separate from elaboration phase
do { do {
wait(SC_ZERO_TIME); wait(SC_ZERO_TIME);
@ -391,7 +391,7 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::run() {
sc_stop(); sc_stop();
} }
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) { bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) {
auto& dmi_lut = is_fetch ? fetch_lut : read_lut; auto& dmi_lut = is_fetch ? fetch_lut : read_lut;
auto lut_entry = dmi_lut.getEntry(addr); 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) { if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
@ -449,7 +449,7 @@ template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem(uint64_t
} }
} }
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem(uint64_t addr, unsigned length, const uint8_t* const data) { bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t* const data) {
auto lut_entry = write_lut.getEntry(addr); 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) { if(lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && addr + length <= lut_entry.get_end_address() + 1) {
auto offset = addr - lut_entry.get_start_address(); auto offset = addr - lut_entry.get_start_address();
@ -497,7 +497,7 @@ template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem(uint64_t
} }
} }
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) { bool core_complex::read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) {
tlm::tlm_generic_payload gp; tlm::tlm_generic_payload gp;
gp.set_command(tlm::TLM_READ_COMMAND); gp.set_command(tlm::TLM_READ_COMMAND);
gp.set_address(addr); gp.set_address(addr);
@ -507,7 +507,7 @@ template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::read_mem_dbg(uint6
return dbus->transport_dbg(gp) == length; return dbus->transport_dbg(gp) == length;
} }
template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) { bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) {
write_buf.resize(length); write_buf.resize(length);
std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity std::copy(data, data + length, write_buf.begin()); // need to copy as TLM does not guarantee data integrity
tlm::tlm_generic_payload gp; tlm::tlm_generic_payload gp;
@ -518,10 +518,5 @@ template <unsigned int BUSWIDTH> bool core_complex<BUSWIDTH>::write_mem_dbg(uint
gp.set_streaming_width(length); gp.set_streaming_width(length);
return dbus->transport_dbg(gp) == 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 tgfs */
} /* namespace sysc */ } /* namespace sysc */

View File

@ -33,7 +33,6 @@
#ifndef _SYSC_CORE_COMPLEX_H_ #ifndef _SYSC_CORE_COMPLEX_H_
#define _SYSC_CORE_COMPLEX_H_ #define _SYSC_CORE_COMPLEX_H_
#include <scc/signal_opt_ports.h>
#include <scc/tick2time.h> #include <scc/tick2time.h>
#include <scc/traceable.h> #include <scc/traceable.h>
#include <scc/utilities.h> #include <scc/utilities.h>
@ -41,8 +40,10 @@
#include <tlm/scc/scv/tlm_rec_initiator_socket.h> #include <tlm/scc/scv/tlm_rec_initiator_socket.h>
#ifdef CWR_SYSTEMC #ifdef CWR_SYSTEMC
#include <scmlinc/scml_property.h> #include <scmlinc/scml_property.h>
#define SOCKET_WIDTH 32
#else #else
#include <cci_configuration> #include <cci_configuration>
#define SOCKET_WIDTH scc::LT
#endif #endif
#include <memory> #include <memory>
#include <tlm> #include <tlm>
@ -67,35 +68,12 @@ public:
namespace tgfs { namespace tgfs {
class core_wrapper; class core_wrapper;
struct core_trace; struct core_trace;
struct core_complex_if {
virtual ~core_complex_if() = default; class core_complex : public sc_core::sc_module, public scc::traceable {
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: public:
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<BUSWIDTH>> ibus{"ibus"}; tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> ibus{"ibus"};
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<BUSWIDTH>> dbus{"dbus"}; tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<SOCKET_WIDTH>> dbus{"dbus"};
sc_core::sc_in<bool> rst_i{"rst_i"}; sc_core::sc_in<bool> rst_i{"rst_i"};
@ -110,6 +88,8 @@ public:
#ifndef CWR_SYSTEMC #ifndef CWR_SYSTEMC
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"}; sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
sc_core::sc_port<tlm::tlm_peek_if<uint64_t>, 1, sc_core::SC_ZERO_OR_MORE_BOUND> mtime_o{"mtime_o"};
cci::cci_param<std::string> elf_file{"elf_file", ""}; cci::cci_param<std::string> elf_file{"elf_file", ""};
cci::cci_param<bool> enable_disass{"enable_disass", false}; cci::cci_param<bool> enable_disass{"enable_disass", false};
@ -135,6 +115,8 @@ public:
#else #else
sc_core::sc_in<bool> clk_i{"clk_i"}; 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<std::string> elf_file{"elf_file", ""};
scml_property<bool> enable_disass{"enable_disass", false}; scml_property<bool> enable_disass{"enable_disass", false};
@ -177,13 +159,13 @@ public:
~core_complex(); ~core_complex();
unsigned get_last_bus_cycles() override { inline unsigned get_last_bus_cycles() {
auto mem_incr = std::max(ibus_inc, dbus_inc); auto mem_incr = std::max(ibus_inc, dbus_inc);
ibus_inc = dbus_inc = 0; ibus_inc = dbus_inc = 0;
return mem_incr > 1 ? mem_incr : 1; return mem_incr > 1 ? mem_incr : 1;
} }
void sync(uint64_t cycle) override { inline void sync(uint64_t cycle) {
auto core_inc = curr_clk * (cycle - last_sync_cycle); auto core_inc = curr_clk * (cycle - last_sync_cycle);
quantum_keeper.inc(core_inc); quantum_keeper.inc(core_inc);
if(quantum_keeper.need_sync()) { if(quantum_keeper.need_sync()) {
@ -193,22 +175,20 @@ public:
last_sync_cycle = cycle; last_sync_cycle = cycle;
} }
bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch) override; bool read_mem(uint64_t addr, unsigned length, uint8_t* const data, bool is_fetch);
bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data) override; bool write_mem(uint64_t addr, unsigned length, const uint8_t* const data);
bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data) override; bool read_mem_dbg(uint64_t addr, unsigned length, uint8_t* const data);
bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data) override; bool write_mem_dbg(uint64_t addr, unsigned length, const uint8_t* const data);
void trace(sc_core::sc_trace_file* trf) const override; void trace(sc_core::sc_trace_file* trf) const override;
bool disass_output(uint64_t pc, const std::string instr) override; bool disass_output(uint64_t pc, const std::string instr);
void set_clock_period(sc_core::sc_time period); void set_clock_period(sc_core::sc_time period);
char const* hier_name() override { return name(); }
protected: protected:
void before_end_of_elaboration() override; void before_end_of_elaboration() override;
void start_of_simulation() override; void start_of_simulation() override;

View File

@ -46,12 +46,12 @@ using namespace sysc;
volatile std::array<bool, 2> tgc_init = { volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|interp", iss_factory::instance().register_creator("tgc5c|m_p|interp",
[](unsigned gdb_port, void* data) -> iss_factory::base_t { [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); 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)}}; 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 { 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_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); 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)}}; 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 = { volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|llvm", iss_factory::instance().register_creator("tgc5c|m_p|llvm",
[](unsigned gdb_port, void* data) -> iss_factory::base_t { [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); 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)}}; 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 { 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_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); 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)}}; 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 = { volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|tcc", iss_factory::instance().register_creator("tgc5c|m_p|tcc",
[](unsigned gdb_port, void* data) -> iss_factory::base_t { [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); 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)}}; 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 { 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_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); 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)}}; 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 = { volatile std::array<bool, 2> tgc_init = {
iss_factory::instance().register_creator("tgc5c|m_p|asmjit", iss_factory::instance().register_creator("tgc5c|m_p|asmjit",
[](unsigned gdb_port, void* data) -> iss_factory::base_t { [](unsigned gdb_port, void* data) -> iss_factory::base_t {
auto cc = reinterpret_cast<sysc::tgfs::core_complex_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); 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)}}; 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 { 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_if*>(data); auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); 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)}}; return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}};
})}; })};

View File

@ -21,7 +21,7 @@ public:
using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t; using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t;
using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t; using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type; using heart_state_t = typename PLAT::hart_state_type;
sc_core_adapter(sysc::tgfs::core_complex_if* owner) sc_core_adapter(sysc::tgfs::core_complex* owner)
: owner(owner) {} : owner(owner) {}
iss::arch_if* get_arch_if() override { return this; } iss::arch_if* get_arch_if() override { return this; }
@ -54,9 +54,9 @@ public:
std::stringstream s; std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2) 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 << "]"; << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount + this->cycle_offset << "]";
SCCDEBUG(owner->hier_name()) << "disass: " SCCDEBUG(owner->name()) << "disass: "
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setw(40) << std::setfill(' ') << std::left << instr << s.str(); << std::setfill(' ') << std::left << instr << s.str();
} }
}; };
@ -79,10 +79,10 @@ public:
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
SCCINFO(owner->hier_name()) SCCINFO(owner->name())
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation"; << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
} else { } else {
SCCINFO(owner->hier_name()) SCCINFO(owner->name())
<< "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation"; << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
@ -112,8 +112,21 @@ public:
} }
iss::status read_csr(unsigned addr, reg_t& val) override { 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)) { if((addr == iss::arch::time || addr == iss::arch::timeh)) {
uint64_t time_val = owner->mtime_i.get_interface() ? owner->mtime_i.read() : 0; uint64_t time_val = owner->mtime_i.read();
if(addr == iss::arch::time) { if(addr == iss::arch::time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if(addr == iss::arch::timeh) { } else if(addr == iss::arch::timeh) {
@ -122,13 +135,14 @@ public:
val = static_cast<reg_t>(time_val >> 32); val = static_cast<reg_t>(time_val >> 32);
} }
return iss::Ok; return iss::Ok;
#endif
} else { } else {
return PLAT::read_csr(addr, val); return PLAT::read_csr(addr, val);
} }
} }
void wait_until(uint64_t flags) override { void wait_until(uint64_t flags) override {
SCCDEBUG(owner->hier_name()) << "Sleeping until interrupt"; SCCDEBUG(owner->name()) << "Sleeping until interrupt";
while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) {
sc_core::wait(wfi_evt); sc_core::wait(wfi_evt);
} }
@ -159,11 +173,11 @@ public:
this->csr[iss::arch::mip] &= ~mask; this->csr[iss::arch::mip] &= ~mask;
this->check_interrupt(); this->check_interrupt();
if(value) if(value)
SCCTRACE(owner->hier_name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
} }
private: private:
sysc::tgfs::core_complex_if* const owner{nullptr}; sysc::tgfs::core_complex* const owner;
sc_core::sc_event wfi_evt; sc_core::sc_event wfi_evt;
uint64_t hostvar{std::numeric_limits<uint64_t>::max()}; uint64_t hostvar{std::numeric_limits<uint64_t>::max()};
unsigned to_host_wr_cnt = 0; unsigned to_host_wr_cnt = 0;

537
src/vm/asmjit/helper_func.h Normal file
View File

@ -0,0 +1,537 @@
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

View File

@ -33,7 +33,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "fp_functions.h" #include "fp_functions.h"
#include <array>
extern "C" { extern "C" {
#include "internals.h" #include "internals.h"
@ -44,10 +43,9 @@ extern "C" {
#include <limits> #include <limits>
using this_t = uint8_t*; using this_t = uint8_t*;
// this does not inlcude any reserved rm or the DYN rm, as DYN rm should be taken care of in the vm_impl const uint8_t rmm_map[] = {
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_even /*RNE*/, softfloat_round_minMag /*RTZ*/, softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/,
softfloat_round_near_maxMag /*RMM*/ softfloat_round_near_maxMag /*RMM*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/, softfloat_round_max /*RTZ*/,
}; };
const uint32_t quiet_nan32 = 0x7fC00000; const uint32_t quiet_nan32 = 0x7fC00000;
@ -58,7 +56,7 @@ uint32_t fget_flags() { return softfloat_exceptionFlags & 0x1f; }
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) { uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r = f32_add(v1f, v2f); float32_t r = f32_add(v1f, v2f);
return r.v; return r.v;
@ -66,7 +64,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) { uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r = f32_sub(v1f, v2f); float32_t r = f32_sub(v1f, v2f);
return r.v; return r.v;
@ -74,7 +72,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) { uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r = f32_mul(v1f, v2f); float32_t r = f32_mul(v1f, v2f);
return r.v; return r.v;
@ -82,7 +80,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) { uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2}; float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r = f32_div(v1f, v2f); float32_t r = f32_div(v1f, v2f);
return r.v; return r.v;
@ -90,7 +88,7 @@ uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
uint32_t fsqrt_s(uint32_t v1, uint8_t mode) { uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
float32_t v1f{v1}; float32_t v1f{v1};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r = f32_sqrt(v1f); float32_t r = f32_sqrt(v1f);
return r.v; return r.v;
@ -132,18 +130,18 @@ uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float32_t r; float32_t r;
switch(op) { switch(op) {
case 0: { // FCVT__W__S case 0: { // w->s, fp to int32
uint_fast32_t res = f32_to_i32(v1f, rmm_map.at(mode), true); uint_fast32_t res = f32_to_i32(v1f, rmm_map[mode & 0x7], true);
return (uint32_t)res; return (uint32_t)res;
} }
case 1: { // FCVT__WU__S case 1: { // wu->s
uint_fast32_t res = f32_to_ui32(v1f, rmm_map.at(mode), true); uint_fast32_t res = f32_to_ui32(v1f, rmm_map[mode & 0x7], true);
return (uint32_t)res; return (uint32_t)res;
} }
case 2: // FCVT__S__W case 2: // s->w
r = i32_to_f32((int32_t)v1); r = i32_to_f32(v1);
return r.v; return r.v;
case 3: // FCVT__S__WU case 3: // s->wu
r = ui32_to_f32(v1); r = ui32_to_f32(v1);
return r.v; return r.v;
} }
@ -151,24 +149,12 @@ 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) { uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode) {
uint32_t F32_SIGN = 1UL << 31; // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
switch(op) { softfloat_roundingMode = rmm_map[mode & 0x7];
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; softfloat_exceptionFlags = 0;
float32_t res = softfloat_mulAddF32(v1, v2, v3, 0); float32_t res = softfloat_mulAddF32(v1, v2, v3, op & 0x1);
if(op > 1)
res.v ^= 1ULL << 31;
return res.v; return res.v;
} }
@ -203,8 +189,8 @@ uint32_t fclass_s(uint32_t v1) {
uA.f = a; uA.f = a;
uiA = uA.ui; uiA = uA.ui;
bool infOrNaN = expF32UI(uiA) == 0xFF; uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF;
bool subnormalOrZero = expF32UI(uiA) == 0; uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0;
bool sign = signF32UI(uiA); bool sign = signF32UI(uiA);
bool fracZero = fracF32UI(uiA) == 0; bool fracZero = fracF32UI(uiA) == 0;
bool isNaN = isNaNF32UI(uiA); bool isNaN = isNaNF32UI(uiA);
@ -217,13 +203,9 @@ uint32_t fclass_s(uint32_t v1) {
} }
uint32_t fconv_d2f(uint64_t v1, uint8_t mode) { uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
bool isNan = isNaNF64UI(v1); softfloat_roundingMode = rmm_map[mode & 0x7];
bool isSNaN = softfloat_isSigNaNF64UI(v1); bool nan = (v1 & defaultNaNF64UI) == defaultNaNF64UI;
softfloat_roundingMode = rmm_map.at(mode); if(nan) {
softfloat_exceptionFlags = 0;
if(isNan) {
if(isSNaN)
softfloat_raiseFlags(softfloat_flag_invalid);
return defaultNaNF32UI; return defaultNaNF32UI;
} else { } else {
float32_t res = f64_to_f32(float64_t{v1}); float32_t res = f64_to_f32(float64_t{v1});
@ -232,11 +214,11 @@ uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
} }
uint64_t fconv_f2d(uint32_t v1, uint8_t mode) { uint64_t fconv_f2d(uint32_t v1, uint8_t mode) {
bool infOrNaN = expF32UI(v1) == 0xFF; bool nan = (v1 & defaultNaNF32UI) == defaultNaNF32UI;
bool subnormalOrZero = expF32UI(v1) == 0; if(nan) {
if(infOrNaN || subnormalOrZero) {
return defaultNaNF64UI; return defaultNaNF64UI;
} else { } else {
softfloat_roundingMode = rmm_map[mode & 0x7];
float64_t res = f32_to_f64(float32_t{v1}); float64_t res = f32_to_f64(float32_t{v1});
return res.v; return res.v;
} }
@ -246,7 +228,7 @@ uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32; bool nan = (v1 & defaultNaNF32UI) == quiet_nan32;
bool snan = softfloat_isSigNaNF32UI(v1); bool snan = softfloat_isSigNaNF32UI(v1);
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r = f64_add(v1f, v2f); float64_t r = f64_add(v1f, v2f);
return r.v; return r.v;
@ -254,7 +236,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) { uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r = f64_sub(v1f, v2f); float64_t r = f64_sub(v1f, v2f);
return r.v; return r.v;
@ -262,7 +244,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) { uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r = f64_mul(v1f, v2f); float64_t r = f64_mul(v1f, v2f);
return r.v; return r.v;
@ -270,7 +252,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) { uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2}; float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r = f64_div(v1f, v2f); float64_t r = f64_div(v1f, v2f);
return r.v; return r.v;
@ -278,7 +260,7 @@ uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
uint64_t fsqrt_d(uint64_t v1, uint8_t mode) { uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
float64_t v1f{v1}; float64_t v1f{v1};
softfloat_roundingMode = rmm_map.at(mode); softfloat_roundingMode = rmm_map[mode & 0x7];
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r = f64_sqrt(v1f); float64_t r = f64_sqrt(v1f);
return r.v; return r.v;
@ -316,23 +298,22 @@ 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) { uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
float64_t v1f{v1}; float64_t v1f{v1};
softfloat_exceptionFlags = 0; softfloat_exceptionFlags = 0;
float64_t r; float64_t r;
switch(op) { switch(op) {
case 0: { // l from d case 0: { // l->d, fp to int32
int64_t res = f64_to_i64(v1f, rmm_map.at(mode), true); int64_t res = f64_to_i64(v1f, rmm_map[mode & 0x7], true);
return (uint64_t)res; return (uint64_t)res;
} }
case 1: { // lu from d case 1: { // lu->s
uint64_t res = f64_to_ui64(v1f, rmm_map.at(mode), true); uint64_t res = f64_to_ui64(v1f, rmm_map[mode & 0x7], true);
return res; return res;
} }
case 2: // d from l case 2: // s->l
r = i64_to_f64(v1); r = i64_to_f64(v1);
return r.v; return r.v;
case 3: // d from lu case 3: // s->lu
r = ui64_to_f64(v1); r = ui64_to_f64(v1);
return r.v; return r.v;
} }
@ -340,24 +321,12 @@ 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) { uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode) {
uint64_t F64_SIGN = 1ULL << 63; // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
switch(op) { softfloat_roundingMode = rmm_map[mode & 0x7];
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; softfloat_exceptionFlags = 0;
float64_t res = softfloat_mulAddF64(v1, v2, v3, 0); float64_t res = softfloat_mulAddF64(v1, v2, v3, op & 0x1);
if(op > 1)
res.v ^= 1ULL << 63;
return res.v; return res.v;
} }
@ -393,8 +362,8 @@ uint64_t fclass_d(uint64_t v1) {
uA.f = a; uA.f = a;
uiA = uA.ui; uiA = uA.ui;
bool infOrNaN = expF64UI(uiA) == 0x7FF; uint_fast16_t infOrNaN = expF64UI(uiA) == 0x7FF;
bool subnormalOrZero = expF64UI(uiA) == 0; uint_fast16_t subnormalOrZero = expF64UI(uiA) == 0;
bool sign = signF64UI(uiA); bool sign = signF64UI(uiA);
bool fracZero = fracF64UI(uiA) == 0; bool fracZero = fracF64UI(uiA) == 0;
bool isNaN = isNaNF64UI(uiA); bool isNaN = isNaNF64UI(uiA);
@ -412,9 +381,9 @@ uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode) {
float64_t r; float64_t r;
switch(op) { switch(op) {
case 0: // l->s, fp to int32 case 0: // l->s, fp to int32
return f32_to_i64(v1f, rmm_map.at(mode), true); return f32_to_i64(v1f, rmm_map[mode & 0x7], true);
case 1: // wu->s case 1: // wu->s
return f32_to_ui64(v1f, rmm_map.at(mode), true); return f32_to_ui64(v1f, rmm_map[mode & 0x7], true);
case 2: // s->w case 2: // s->w
r = i32_to_f64(v1); r = i32_to_f64(v1);
return r.v; return r.v;
@ -430,11 +399,11 @@ uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode) {
float32_t r; float32_t r;
switch(op) { switch(op) {
case 0: { // wu->s case 0: { // wu->s
int32_t r = f64_to_i32(float64_t{v1}, rmm_map.at(mode), true); int32_t r = f64_to_i32(float64_t{v1}, rmm_map[mode & 0x7], true);
return r; return r;
} }
case 1: { // wu->s case 1: { // wu->s
uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map.at(mode), true); uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map[mode & 0x7], true);
return r; return r;
} }
case 2: // l->s, fp to int32 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