cmake_minimum_required(VERSION 3.18)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

# ##############################################################################
#
# ##############################################################################
project(dbt-rise-tgc VERSION 1.0.0)

include(GNUInstallDirs)
include(flink)

find_package(elfio QUIET)
find_package(jsoncpp)
find_package(Boost COMPONENTS coroutine REQUIRED)

add_subdirectory(softfloat)

set(LIB_SOURCES
    src/iss/plugin/instruction_count.cpp
    src/iss/arch/tgc5c.cpp
    src/iss/mem/memory_if.cpp
    src/vm/interp/vm_tgc5c.cpp
    src/vm/fp_functions.cpp
    src/vm/vector_functions.cpp
    src/iss/debugger/csr_names.cpp
    src/iss/semihosting/semihosting.cpp
)

if(WITH_TCC)
    list(APPEND LIB_SOURCES
        src/vm/tcc/vm_tgc5c.cpp
    )
endif()

if(WITH_LLVM)
    list(APPEND LIB_SOURCES
        src/vm/llvm/vm_tgc5c.cpp
        src/vm/llvm/fp_impl.cpp
    )
endif()

if(WITH_ASMJIT)
    list(APPEND LIB_SOURCES
        src/vm/asmjit/vm_tgc5c.cpp
    )
endif()

# library files
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
FILE(GLOB GEN_YAML_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/contrib/instr/*.yaml)
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})

foreach(FILEPATH ${GEN_ISS_SOURCES})
    get_filename_component(CORE ${FILEPATH} NAME_WE)
    string(TOUPPER ${CORE} CORE)
    list(APPEND LIB_DEFINES CORE_${CORE})
endforeach()

message(STATUS "Core defines are ${LIB_DEFINES}")

if(WITH_LLVM)
    FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp)
    list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
endif()

if(WITH_TCC)
    FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
    list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif()

if(WITH_ASMJIT)
    FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/asmjit/vm_*.cpp)
    list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif()

if(TARGET yaml-cpp::yaml-cpp)
    list(APPEND LIB_SOURCES
        src/iss/plugin/cycle_estimate.cpp
        src/iss/plugin/instruction_count.cpp
    )
endif()

# Define the library
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif()

target_include_directories(${PROJECT_NAME} PUBLIC src)
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)

target_force_link_libraries(${PROJECT_NAME} PRIVATE dbt-rise-core)

# only re-export the include paths
get_target_property(DBT_CORE_INCL dbt-rise-core INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${PROJECT_NAME} INTERFACE ${DBT_CORE_INCL})
get_target_property(DBT_CORE_DEFS dbt-rise-core INTERFACE_COMPILE_DEFINITIONS)

if(NOT(DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND))
    target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS})
endif()

target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine)

if(TARGET yaml-cpp::yaml-cpp)
    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS)
    target_link_libraries(${PROJECT_NAME} PUBLIC yaml-cpp::yaml-cpp)
endif()

set_target_properties(${PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    FRAMEWORK FALSE
)
install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
    EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
    FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss COMPONENT ${PROJECT_NAME}
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # target directory
    FILES_MATCHING # install only matched files
    PATTERN "*.h" # select header files
)
install(FILES ${GEN_YAML_SOURCES} DESTINATION share/tgc-vp)

# ##############################################################################
#
# ##############################################################################
set(CMAKE_INSTALL_RPATH $ORIGIN/../${CMAKE_INSTALL_LIBDIR})
project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED)

add_executable(${PROJECT_NAME} src/main.cpp)

if(TARGET ${CORE_NAME}_cpp)
    list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
else()
    FILE(GLOB TGC_SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
    )
    list(APPEND TGC_SOURCES ${GEN_SOURCES})
endif()

foreach(F IN LISTS TGC_SOURCES)
    if(${F} MATCHES ".*/arch/([^/]*)\.cpp")
        string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
        string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
        target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
    endif()
endforeach()

# if(WITH_LLVM)
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
# #target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
# endif()
# if(WITH_TCC)
# target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
# endif()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc fmt::fmt)

if(TARGET Boost::program_options)
    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
else()
    target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY})
endif()

target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})

if(Tcmalloc_FOUND)
    target_link_libraries(${PROJECT_NAME} PUBLIC ${Tcmalloc_LIBRARIES})
endif(Tcmalloc_FOUND)

install(TARGETS tgc-sim
    EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
    FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} # headers for mac (note the different component -> different package)
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
)

if(BUILD_TESTING)
    # ... CMake code to create tests ...
    add_test(NAME tgc-sim-interp
        COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend interp)

    if(WITH_TCC)
        add_test(NAME tgc-sim-tcc
            COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend tcc)
    endif()

    if(WITH_LLVM)
        add_test(NAME tgc-sim-llvm
            COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend llvm)
    endif()

    if(WITH_ASMJIT)
        add_test(NAME tgc-sim-asmjit
            COMMAND tgc-sim -f ${CMAKE_BINARY_DIR}/../../Firmwares/hello-world/hello --backend asmjit)
    endif()
endif()

# ##############################################################################
#
# ##############################################################################
if(TARGET scc-sysc)
    project(dbt-rise-tgc_sc VERSION 1.0.0)
    set(LIB_SOURCES
        src/sysc/core_complex.cpp
        src/sysc/register_tgc_c.cpp
    )
    FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/sysc/register_*.cpp)
    list(APPEND LIB_SOURCES ${GEN_SC_SOURCES})
    add_library(${PROJECT_NAME} ${LIB_SOURCES})
    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})

    foreach(F IN LISTS TGC_SOURCES)
        if(${F} MATCHES ".*/arch/([^/]*)\.cpp")
            string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
            string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
            target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
        endif()
    endforeach()

    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)

    # if(WITH_LLVM)
    # target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
    # endif()
    set(LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/sysc/core_complex.h)
    set_target_properties(${PROJECT_NAME} PROPERTIES
        VERSION ${PROJECT_VERSION}
        FRAMEWORK FALSE
        PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
    )
    install(TARGETS ${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
        EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # static lib
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # binaries
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # shared lib
        FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # for mac
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sysc # headers for mac (note the different component -> different package)
        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
    )
endif()

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)
