Skip to content

Commit

Permalink
GHDL support vhpidirect
Browse files Browse the repository at this point in the history
  • Loading branch information
Risto97 committed Feb 12, 2025
1 parent 5c5ba00 commit 4ace065
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 71 deletions.
2 changes: 0 additions & 2 deletions cmake/sim/cadence/xcelium.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ function(xcelium IP_LIB)
set(ARG_VHDL_COMPILE_ARGS VHDL_COMPILE_ARGS ${ARG_VHDL_COMPILE_ARGS})
endif()

get_ip_links(IPS_LIST ${IP_LIB})

if(NOT TARGET ${IP_LIB}_xcelium_complib)
__xcelium_compile_lib(${IP_LIB}
OUTDIR ${OUTDIR}
Expand Down
194 changes: 125 additions & 69 deletions cmake/sim/ghdl/ghdl.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function(__ghdl_get_standard_arg OUTVAR)
endfunction()

function(ghdl IP_LIB)
cmake_parse_arguments(ARG "NO_RUN_TARGET;" "OUTDIR;TOP_MODULE;EXECUTABLE_NAME;STANDARD" "ANALYZE_ARGS;ELABORATE_ARGS;RUN_ARGS" ${ARGN})
cmake_parse_arguments(ARG "NO_RUN_TARGET;" "OUTDIR;TOP_MODULE;EXECUTABLE_NAME;STANDARD" "VHDL_COMPILE_ARGS;ELABORATE_ARGS;RUN_ARGS" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
endif()
Expand All @@ -23,26 +23,30 @@ function(ghdl IP_LIB)
alias_dereference(IP_LIB ${IP_LIB})
get_target_property(BINARY_DIR ${IP_LIB} BINARY_DIR)

if(NOT ARG_OUTDIR)
set(OUTDIR ${BINARY_DIR}/${IP_LIB}_ghdl)
else()
set(OUTDIR ${ARG_OUTDIR})
endif()
file(MAKE_DIRECTORY ${OUTDIR})

get_target_property(LIBRARY ${IP_LIB} LIBRARY)
if(NOT LIBRARY)
set(LIBRARY work)
endif()
if(ARG_LIBRARY)
set(LIBRARY ${ARG_LIBRARY})
set(ARG_LIBRARY LIBRARY ${LIBRARY})
endif()

if(NOT ARG_TOP_MODULE)
get_target_property(ARG_TOP_MODULE ${IP_LIB} IP_NAME)
endif()

if(NOT ARG_OUTDIR)
set(OUTDIR ${BINARY_DIR}/${IP_LIB}_ghdl)
else()
set(OUTDIR ${ARG_OUTDIR})
endif()
file(MAKE_DIRECTORY ${OUTDIR})

__ghdl_get_standard_arg(STANDARD ${ARG_STANDARD})

if(ARG_ANALYZE_ARGS)
set(ARG_ANALYZE_ARGS ANALYZE_ARGS ${ARG_ANALYZE_ARGS})
if(ARG_VHDL_COMPILE_ARGS)
set(ARG_VHDL_COMPILE_ARGS VHDL_COMPILE_ARGS ${ARG_VHDL_COMPILE_ARGS})
endif()

if(NOT ARG_EXECUTABLE_NAME)
Expand All @@ -51,13 +55,22 @@ function(ghdl IP_LIB)
set(SIM_EXEC_PATH "${OUTDIR}/${ARG_EXECUTABLE_NAME}")

##### GHDL Analyze
__ghdl_compile_lib(${IP_LIB}
OUTDIR ${OUTDIR}
STANDARD ${STANDARD}
${ARG_ANALYZE_ARGS}
)
if(NOT TARGET ${IP_LIB}_ghdl_complib)
__ghdl_compile_lib(${IP_LIB}
OUTDIR ${OUTDIR}
STANDARD ${STANDARD}
${ARG_LIBRARY}
${ARG_VHDL_COMPILE_ARGS}
)
endif()
set(__comp_tgt ${IP_LIB}_ghdl_complib)

__get_ghdl_search_lib_args(${IP_LIB}
${ARG_LIBRARY}
OUTDIR ${OUTDIR})
set(hdl_libs_args ${HDL_LIBS_ARGS})
set(dpi_libs_args ${DPI_LIBS_ARGS})

##### GHDL Elaborate
if(NOT TARGET ${IP_LIB}_ghdl)
get_ip_sources(VHDL_SOURCES ${IP_LIB} VHDL)
Expand All @@ -67,7 +80,7 @@ function(ghdl IP_LIB)
-o ${SIM_EXEC_PATH}
--workdir=${OUTDIR}/${LIBRARY}
${ARG_ELABORATE_ARGS}
${LIB_SEARCH_DIRS}
${hdl_libs_args} ${dpi_libs_args}
${LIBRARY}.${ARG_TOP_MODULE}
)

Expand All @@ -93,6 +106,13 @@ function(ghdl IP_LIB)
set_property(TARGET ${IP_LIB}_ghdl PROPERTY DESCRIPTION ${DESCRIPTION})
endif()

# set(__ghdl_run_cmd ghdl run
# --std=${STANDARD}
# --workdir=${OUTDIR}/${LIBRARY}
# ${ARG_RUN_ARGS}
# ${LIB_SEARCH_DIRS}
# ${LIBRARY}.${ARG_TOP_MODULE})

set(__ghdl_run_cmd ${SIM_EXEC_PATH} ${ARG_RUN_ARGS})
if(NOT ARG_NO_RUN_TARGET)
if(NOT ARG_RUN_TARGET_NAME)
Expand All @@ -112,7 +132,7 @@ function(ghdl IP_LIB)
endfunction()

function(__ghdl_compile_lib IP_LIB)
cmake_parse_arguments(ARG "" "LIBRARY;OUTDIR;STANDARD" "ANALYZE_ARGS" ${ARGN})
cmake_parse_arguments(ARG "" "LIBRARY;OUTDIR;STANDARD" "VHDL_COMPILE_ARGS" ${ARGN})
# Check for any unrecognized arguments
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
Expand All @@ -132,8 +152,10 @@ function(__ghdl_compile_lib IP_LIB)

__ghdl_get_standard_arg(STANDARD ${ARG_STANDARD})

# Find the GHDL tools/include directory, needed for VPI/VHPI libraries
__add_ghdl_cxx_properties_to_libs(${IP_LIB})

get_ip_links(__ips ${IP_LIB})
unset(lib_search_dirs)
unset(all_obj_files)
foreach(lib ${__ips})

Expand All @@ -147,26 +169,27 @@ function(__ghdl_compile_lib IP_LIB)
set(__comp_lib_name ${ARG_LIBRARY})
endif()

# Create output directoy for the VHDL library
set(lib_outdir ${OUTDIR}/${__comp_lib_name})
file(MAKE_DIRECTORY ${lib_outdir})

__get_ghdl_search_lib_args(${lib}
OUTDIR ${OUTDIR})
set(hdl_libs_args ${HDL_LIBS_ARGS})

# VHDL files and arguments
get_ip_sources(VHDL_SOURCES ${lib} VHDL NO_DEPS)
set(__ghdl_analyze_cmd ghdl analyze
--std=${STANDARD}
-fsynopsys
--work=${__comp_lib_name}
--workdir=${OUTDIR}/${__comp_lib_name}
${ARG_ANALYZE_ARGS}
${lib_search_dirs} # This is not correct, as it should include only SUBIPs search directories TODO
${ARG_VHDL_COMPILE_ARGS}
${hdl_libs_args}
${VHDL_SOURCES}
)


# Create output directoy for the VHDL library
set(lib_outdir ${OUTDIR}/${__comp_lib_name})
file(MAKE_DIRECTORY ${lib_outdir})

# Append current library outdir to list of search directories
list(APPEND lib_search_dirs -P${lib_outdir})

# GHDL creates an object (.o) file for each VHDL source file
# GHDL creates a .cf file for each VHDL library
unset(obj_files)
Expand All @@ -189,16 +212,18 @@ function(__ghdl_compile_lib IP_LIB)
list(APPEND __ghdl_subdep_obj_files ${__ghdl_${ip_dep}_obj_files})
endforeach()

set(DESCRIPTION "Compile VHDL for ${lib} with ghdl in library ${__comp_lib_name}")
set(STAMP_FILE "${BINARY_DIR}/${lib}_${CMAKE_CURRENT_FUNCTION}.stamp")
add_custom_command(
OUTPUT ${obj_files}
COMMAND ${__ghdl_analyze_cmd}
BYPRODUCTS ${cf_files}
WORKING_DIRECTORY ${OUTDIR}
DEPENDS ${VHDL_SOURCES} ${__ghdl_subdep_obj_files}
COMMENT ${DESCRIPTION}
)
if(VHDL_SOURCES)
set(DESCRIPTION "Compile VHDL for ${lib} with ghdl in library ${__comp_lib_name}")
set(STAMP_FILE "${BINARY_DIR}/${lib}_${CMAKE_CURRENT_FUNCTION}.stamp")
add_custom_command(
OUTPUT ${obj_files}
COMMAND ${__ghdl_analyze_cmd}
BYPRODUCTS ${cf_files}
WORKING_DIRECTORY ${OUTDIR}
DEPENDS ${VHDL_SOURCES} ${__ghdl_subdep_obj_files}
COMMENT ${DESCRIPTION}
)
endif()

list(APPEND all_obj_files ${obj_files})
endforeach()
Expand All @@ -211,38 +236,69 @@ function(__ghdl_compile_lib IP_LIB)
set_property(TARGET ${IP_LIB}_ghdl_complib PROPERTY DESCRIPTION
"Compile VHDL files for ${IP_LIB} with ghdl")
endif()
set(LIB_SEARCH_DIRS ${lib_search_dirs} PARENT_SCOPE)

endfunction()

## Parallel analysis
# unset(obj_files)
# set(cf_file "${lib_outdir}/${__comp_lib_name}-obj${STANDARD}.cf")
# foreach(source ${VHDL_SOURCES})
# get_filename_component(source_basename ${source} NAME_WLE)
# set(obj_file "${lib_outdir}/${source_basename}.o")
# message("source: ${obj_file}")
#
# set(__ghdl_analyze_cmd ghdl analyze
# --std=${STANDARD}
# -fsynopsys
# --work=${__comp_lib_name}
# --workdir=${OUTDIR}/${__comp_lib_name}
# ${ARG_ANALYZE_ARGS}
# ${lib_search_dirs}
# ${source}
# )
#
# set(DESCRIPTION "Compile ${source} with ghdl in library ${__comp_lib_name}")
# # set(STAMP_FILE "${BINARY_DIR}/${lib}_${CMAKE_CURRENT_FUNCTION}.stamp")
# add_custom_command(
# OUTPUT ${obj_file}
# COMMAND ${__ghdl_analyze_cmd}
# BYPRODUCTS ${cf_file}
# WORKING_DIRECTORY ${OUTDIR}
# DEPENDS ${all_obj_files}
# COMMENT ${DESCRIPTION}
# )
#
# list(APPEND all_obj_files ${obj_file})
# endforeach()
function(__get_ghdl_search_lib_args IP_LIB)
cmake_parse_arguments(ARG "" "OUTDIR;LIBRARY" "" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
endif()

get_ip_links(ips ${IP_LIB})
unset(hdl_libs_args)
foreach(lib ${ips})
# In case linked library is C/C++ shared/static object, dont try to compile it, just append its path to -sv_lib arg
get_target_property(ip_type ${lib} TYPE)
if(ip_type STREQUAL "SHARED_LIBRARY" OR ip_type STREQUAL "STATIC_LIBRARY")
list(APPEND dpi_libs_args -Wl,$<TARGET_FILE:${lib}>)
if(ip_type STREQUAL "SHARED_LIBRARY")
message(WARNING "Shared library linked to simulation executable, set LD_LIBRARY_PATH")
endif()
else()
# Library of the current IP block, get it from SoCMake library if present
# If neither LIBRARY property is set, or LIBRARY passed as argument, use "work" as default
get_target_property(__comp_lib_name ${lib} LIBRARY)
if(NOT __comp_lib_name)
set(__comp_lib_name work)
endif()
if(ARG_LIBRARY)
set(__comp_lib_name ${ARG_LIBRARY})
endif()

set(lib_outdir ${ARG_OUTDIR}/${__comp_lib_name})
# Append current library outdhdl_libs_argsir to list of search directories
if(NOT "-P${lib_outdir}" IN_LIST hdl_libs_args)
list(APPEND hdl_libs_args -P${lib_outdir})
endif()
endif()
endforeach()

set(HDL_LIBS_ARGS ${hdl_libs_args} PARENT_SCOPE)
set(DPI_LIBS_ARGS ${dpi_libs_args} PARENT_SCOPE)
endfunction()

function(__add_ghdl_cxx_properties_to_libs IP_LIB)
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
endif()
# Find the GHDL tools/include directory, needed for VPI/DPI libraries
find_program(ghdl_exec_path ghdl)
get_filename_component(vpi_inc_path "${ghdl_exec_path}" DIRECTORY)
cmake_path(SET vpi_inc_path NORMALIZE "${vpi_inc_path}/../include/ghdl")

get_ip_links(ips ${IP_LIB})
foreach(lib ${ips})
# In case linked library is C/C++ shared/static object, dont try to compile it, just append its path to -sv_lib arg
get_target_property(ip_type ${lib} TYPE)
if(ip_type STREQUAL "SHARED_LIBRARY" OR ip_type STREQUAL "STATIC_LIBRARY")
if(NOT ghdl_exec_path)
message(FATAL_ERROR "GHDL executable xrun was not found, cannot set include directory on DPI library")
endif()
# Add tools/include directory to the include directories of DPI libraries
# TODO do this only when its needed
target_include_directories(${lib} PUBLIC ${vpi_inc_path})
target_compile_definitions(${lib} PUBLIC GHDL)
endif()
endforeach()
endfunction()
18 changes: 18 additions & 0 deletions examples/vhpidirect/customc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
include("../../../SoCMakeConfig.cmake")
cmake_minimum_required(VERSION 3.25)
project(vhpidirect_customc C)

add_ip(tb)

ip_sources(tb VHDL
./tb.vhd
)

add_library(customc STATIC
./main.c
)

ip_link(${IP}
customc)
ghdl(${IP})

17 changes: 17 additions & 0 deletions examples/vhpidirect/customc/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <stdio.h>

void custom_procedure (void) {
printf("Hello from custom_procedure!\n");
}

void custom_procedure_withargs (int x) {
printf("Hello from custom_procedure '%d'!\n", x);
}

int custom_function (void) {
return 3;
}

int custom_function_withargs (int x) {
return x+5;
}
33 changes: 33 additions & 0 deletions examples/vhpidirect/customc/tb.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
entity tb is
end tb;

architecture arch of tb is

procedure cproc is
begin report "VHPIDIRECT custom_procedure" severity failure; end;
attribute foreign of cproc : procedure is "VHPIDIRECT custom_procedure";

procedure cproc_wargs ( x: integer ) is
begin report "VHPIDIRECT custom_procedure_withargs" severity failure; end;
attribute foreign of cproc_wargs : procedure is "VHPIDIRECT custom_procedure_withargs";

function cfunc return integer is
begin report "VHPIDIRECT custom_function" severity failure; end;
attribute foreign of cfunc : function is "VHPIDIRECT custom_function";

function cfunc_wargs ( x: integer ) return integer is
begin report "VHPIDIRECT custom_function_withargs" severity failure; end;
attribute foreign of cfunc_wargs : function is "VHPIDIRECT custom_function_withargs";

begin

process
begin
cproc;
cproc_wargs(17);
report "cfunc: " & integer'image( cfunc ) severity note;
report "cfunc_wargs: " & integer'image( cfunc_wargs(21) ) severity note;
wait;
end process;

end;

0 comments on commit 4ace065

Please sign in to comment.