From 93fa9d0575d2200b9cb76588db0feb3ab8f1cebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Mon, 25 Nov 2024 23:35:01 +0100 Subject: [PATCH] Add modelsim DPI support, improve modelsim support and add modelsim examples --- cmake/sim/modelsim/modelsim.cmake | 205 +++++++++++------- examples/modelsim/CMakeLists.txt | 21 -- examples/modelsim/dpi/CMakeLists.txt | 20 ++ examples/modelsim/dpi/hello/CMakeLists.txt | 9 + examples/modelsim/dpi/hello/hello.cpp | 7 + examples/modelsim/dpi/tb.sv | 9 + examples/modelsim/parallel/CMakeLists.txt | 23 ++ .../modelsim/parallel/printer/CMakeLists.txt | 14 ++ .../modelsim/parallel/printer/printer.v.in | 5 + examples/modelsim/parallel/tb.v | 41 ++++ examples/modelsim/simple/CMakeLists.txt | 20 ++ .../{ => simple}/adder/CMakeLists.txt | 3 +- .../modelsim/{ => simple}/adder/adder.vhdl | 0 examples/modelsim/{ => simple}/tb.v | 0 14 files changed, 278 insertions(+), 99 deletions(-) delete mode 100644 examples/modelsim/CMakeLists.txt create mode 100644 examples/modelsim/dpi/CMakeLists.txt create mode 100644 examples/modelsim/dpi/hello/CMakeLists.txt create mode 100644 examples/modelsim/dpi/hello/hello.cpp create mode 100644 examples/modelsim/dpi/tb.sv create mode 100644 examples/modelsim/parallel/CMakeLists.txt create mode 100644 examples/modelsim/parallel/printer/CMakeLists.txt create mode 100644 examples/modelsim/parallel/printer/printer.v.in create mode 100644 examples/modelsim/parallel/tb.v create mode 100644 examples/modelsim/simple/CMakeLists.txt rename examples/modelsim/{ => simple}/adder/CMakeLists.txt (57%) rename examples/modelsim/{ => simple}/adder/adder.vhdl (100%) rename examples/modelsim/{ => simple}/tb.v (100%) diff --git a/cmake/sim/modelsim/modelsim.cmake b/cmake/sim/modelsim/modelsim.cmake index f92cb10..02f2fca 100644 --- a/cmake/sim/modelsim/modelsim.cmake +++ b/cmake/sim/modelsim/modelsim.cmake @@ -1,14 +1,15 @@ include_guard(GLOBAL) -function(modelsim_compile_lib IP_LIB) - cmake_parse_arguments(ARG "NO_DEPS" "OUTDIR;ARGS" "" ${ARGN}) - # Check for any unrecognized arguments +function(modelsim IP_LIB) + cmake_parse_arguments(ARG "TARGET_PER_IP;QUIET" "TOP_MODULE;OUTDIR;ARGS" "" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") endif() include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") + find_modelsim(REQUIRED) + alias_dereference(IP_LIB ${IP_LIB}) get_target_property(BINARY_DIR ${IP_LIB} BINARY_DIR) @@ -17,12 +18,130 @@ function(modelsim_compile_lib IP_LIB) set(LIBRARY work) endif() + if(NOT ARG_TOP_MODULE) + get_target_property(IP_NAME ${IP_LIB} IP_NAME) + set(ARG_TOP_MODULE ${IP_NAME}) + endif() + if(NOT ARG_OUTDIR) set(OUTDIR ${BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}) else() set(OUTDIR ${ARG_OUTDIR}) endif() + if(ARG_QUIET) + set(ARG_QUIET QUIET) + endif() + + unset(__lib_args) + unset(__comp_tgts) + + get_ip_links(IPS_LIST ${IP_LIB}) + + # Get all DPI-C compiler libraies and add to list of libraries + foreach(ip ${IPS_LIST}) + get_target_property(ip_type ${ip} TYPE) + if(ip_type STREQUAL "SHARED_LIBRARY" OR ip_type STREQUAL "STATIC_LIBRARY") + list(APPEND __lib_args -sv_lib $/lib$) + endif() + endforeach() + + unset(__libdirs) + unset(__libnames) + if(ARG_TARGET_PER_IP) # In case TARGET_PER_IP is passed, a compile target is created per IP block + set(list_comp_libs ${IPS_LIST}) + set(__no_deps_arg NO_DEPS) + else() # Else only create target for compiling top level IP + set(list_comp_libs ${IP_LIB}) + unset(__no_deps_arg) + endif() + + list(APPEND __lib_args -Ldir ${OUTDIR}) + foreach(ip ${list_comp_libs}) + get_target_property(ip_name ${ip} IP_NAME) + if(ip_name) # If IP_NAME IS set, its SoCMake's IP_LIBRARY + __modelsim_compile_lib(${ip} ${__no_deps_arg} OUTDIR ${OUTDIR} ${ARG_QUIET}) + if(NOT ${MODELSIM_IP_LIB_NAME} IN_LIST __libnames) + list(APPEND __lib_args -L ${MODELSIM_IP_LIB_NAME}) + list(APPEND __libnames ${MODELSIM_IP_LIB_NAME}) + endif() + list(APPEND __comp_tgts ${ip}_modelsim_complib) + endif() + endforeach() + + get_ip_compile_definitions(COMP_DEFS ${IP_LIB} VHDL SYSTEMVERILOG VERILOG) + + foreach(def ${COMP_DEFS}) + list(APPEND CMP_DEFS_ARG +${def}) + endforeach() + + set(__VSIM_CMD ${MODELSIM_HOME}/bin/vsim + ${__lib_args} + ${CMP_DEFS_ARG} + -c ${LIBRARY}.${ARG_TOP_MODULE} + -do "run -all\; quit" + $<$:-quiet> + ) + set(DESCRIPTION "Run ${CMAKE_CURRENT_FUNCTION} testbench compiled from ${IP_LIB}") + add_custom_target( + run_${IP_LIB}_${CMAKE_CURRENT_FUNCTION} + COMMAND ${__VSIM_CMD} -noautoldlibpath + DEPENDS ${__comp_tgts} + WORKING_DIRECTORY ${MODELSIM_IP_LIB_DIR} + COMMENT ${DESCRIPTION} + VERBATIM + ) + set_property(TARGET run_${IP_LIB}_${CMAKE_CURRENT_FUNCTION} PROPERTY DESCRIPTION ${DESCRIPTION}) + +endfunction() + + +function(find_modelsim) + cmake_parse_arguments(ARG "REQUIRED" "" "" ${ARGN}) + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") + endif() + + find_program(VSIM_EXEC vsim + HINTS ${MODELSIM_HOME}/*/ $ENV{MODELSIM_HOME}/*/ + ) + + if(NOT VSIM_EXEC AND ARG_REQUIRED) + message(FATAL_ERROR "Modelsim was not found, please set MODELSIM_HOME, ENV{MODELSIM_HOME} or system PATH variable") + endif() + + if(NOT MODELSIM_HOME) + cmake_path(GET VSIM_EXEC PARENT_PATH __modelsim_bindir) + cmake_path(GET __modelsim_bindir PARENT_PATH MODELSIM_HOME) + set(MODELSIM_HOME ${MODELSIM_HOME} CACHE PATH "Path to Modelsim installation") + mark_as_advanced(MODELSIM_HOME) + endif() + +endfunction() + +function(__modelsim_compile_lib IP_LIB) + cmake_parse_arguments(ARG "QUIET;NO_DEPS" "OUTDIR;ARGS" "" ${ARGN}) + # Check for any unrecognized arguments + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") + endif() + + include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") + + alias_dereference(IP_LIB ${IP_LIB}) + get_target_property(BINARY_DIR ${IP_LIB} BINARY_DIR) + + get_target_property(LIBRARY ${IP_LIB} LIBRARY) + if(NOT LIBRARY) + set(LIBRARY work) + endif() + + if(NOT ARG_OUTDIR) + set(OUTDIR ${BINARY_DIR}/${IP_LIB}_modelsim) + else() + set(OUTDIR ${ARG_OUTDIR}) + endif() + if(ARG_NO_DEPS) set(ARG_NO_DEPS NO_DEPS) else() @@ -45,10 +164,11 @@ function(modelsim_compile_lib IP_LIB) endforeach() set(DESCRIPTION "Compile Verilog and SV files of ${IP_LIB} with modelsim vlog in library ${LIBRARY}") - set(__VLOG_CMD COMMAND vlog + set(__VLOG_CMD COMMAND ${MODELSIM_HOME}/bin/vlog -nologo -sv -sv17compat + $<$:-quiet> ${SV_ARG_INCDIRS} ${SV_CMP_DEFS_ARG} ${SV_SOURCES} @@ -71,8 +191,9 @@ function(modelsim_compile_lib IP_LIB) list(APPEND VHDL_CMP_DEFS_ARG +define+${def}) endforeach() - set(__VCOM_CMD COMMAND vcom + set(__VCOM_CMD COMMAND ${MODELSIM_HOME}/bin/vcom -nologo + $<$:-quiet> ${VHDL_ARG_INCDIRS} ${VHDL_CMP_DEFS_ARG} ${VHDL_SOURCES} @@ -93,83 +214,13 @@ function(modelsim_compile_lib IP_LIB) ) add_custom_target( - ${IP_LIB}_${CMAKE_CURRENT_FUNCTION} + ${IP_LIB}_modelsim_complib DEPENDS ${STAMP_FILE} ${STAMP_FILE_VHDL} ${IP_LIB} ) - set_property(TARGET ${IP_LIB}_${CMAKE_CURRENT_FUNCTION} PROPERTY + set_property(TARGET ${IP_LIB}_modelsim_complib PROPERTY DESCRIPTION "Compile VHDL, SV, and Verilog files for ${IP_LIB} with modelsim in library ${LIBRARY}") set(MODELSIM_IP_LIB_DIR ${OUTDIR} PARENT_SCOPE) set(MODELSIM_IP_LIB_NAME ${LIBRARY} PARENT_SCOPE) endfunction() - -function(modelsim IP_LIB) - # Parse the function arguments - cmake_parse_arguments(ARG "HIER_TARGETS" "TOP_MODULE;OUTDIR;ARGS" "" ${ARGN}) - # Check for any unrecognized arguments - if(ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") - endif() - - include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") - - alias_dereference(IP_LIB ${IP_LIB}) - get_target_property(BINARY_DIR ${IP_LIB} BINARY_DIR) - - get_target_property(LIBRARY ${IP_LIB} LIBRARY) - if(NOT LIBRARY) - set(LIBRARY work) - endif() - - if(NOT ARG_TOP_MODULE) - get_target_property(IP_NAME ${IP_LIB} IP_NAME) - set(ARG_TOP_MODULE ${IP_NAME}) - endif() - - if(NOT ARG_OUTDIR) - set(OUTDIR ${BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}) - else() - set(OUTDIR ${ARG_OUTDIR}) - endif() - - unset(LIB_ARGS) - unset(MODELSIM_COMP_TARGETS) - if(ARG_HIER_TARGETS) - get_ip_links(IPS_LIST ${IP_LIB}) - foreach(ip ${IPS_LIST}) - modelsim_compile_lib(${ip} NO_DEPS) - list(APPEND LIB_ARGS -Ldir ${MODELSIM_IP_LIB_DIR} -L ${MODELSIM_IP_LIB_NAME}) - list(APPEND MODELSIM_COMP_TARGETS ${ip}_modelsim_compile_lib) - endforeach() - else() - modelsim_compile_lib(${IP_LIB}) - list(APPEND LIB_ARGS -Ldir ${MODELSIM_IP_LIB_DIR} -L ${MODELSIM_IP_LIB_NAME}) - list(APPEND MODELSIM_COMP_TARGETS ${IP_LIB}_modelsim_compile_lib) - endif() - - get_ip_compile_definitions(COMP_DEFS ${IP_LIB} VHDL SYSTEMVERILOG VERILOG) - - foreach(def ${COMP_DEFS}) - list(APPEND CMP_DEFS_ARG +${def}) - endforeach() - - set(__VSIM_CMD vsim - ${LIB_ARGS} - ${CMP_DEFS_ARG} - -c ${LIBRARY}.${ARG_TOP_MODULE} - -do "run -all\; quit" - - ) - set(DESCRIPTION "Run ${CMAKE_CURRENT_FUNCTION} testbench compiled from ${IP_LIB}") - add_custom_target( - run_${IP_LIB}_${CMAKE_CURRENT_FUNCTION} - COMMAND ${__VSIM_CMD} - DEPENDS ${MODELSIM_COMP_TARGETS} - COMMENT ${DESCRIPTION} - VERBATIM - ) - set_property(TARGET run_${IP_LIB}_${CMAKE_CURRENT_FUNCTION} PROPERTY DESCRIPTION ${DESCRIPTION}) - -endfunction() - diff --git a/examples/modelsim/CMakeLists.txt b/examples/modelsim/CMakeLists.txt deleted file mode 100644 index 89250c2..0000000 --- a/examples/modelsim/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.25) -project(example NONE) - -# include("deps/deps.cmake") -include("../../SoCMakeConfig.cmake") - -add_ip(cern::ip::tb::0.0.1 - DESCRIPTION "Simple verilog testbench" - ) - -ip_sources(${IP} VERILOG # Add source files to the VERILOG file set - ${PROJECT_SOURCE_DIR}/tb.v - ) - -add_subdirectory(adder) - -ip_link(${IP} vendor::lib::adder::0.0.1) - -modelsim(${IP} HIER_TARGETS) - -help() diff --git a/examples/modelsim/dpi/CMakeLists.txt b/examples/modelsim/dpi/CMakeLists.txt new file mode 100644 index 0000000..facd333 --- /dev/null +++ b/examples/modelsim/dpi/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.25) +project(dpi_example NONE) + +include("../../../SoCMakeConfig.cmake") + +add_ip(tb + DESCRIPTION "Simple verilog testbench" + ) + +ip_sources(${IP} SYSTEMVERILOG + ${PROJECT_SOURCE_DIR}/tb.sv + ) + +add_subdirectory(hello) + +ip_link(${IP} hello_dpi) + +modelsim(${IP}) + +help() diff --git a/examples/modelsim/dpi/hello/CMakeLists.txt b/examples/modelsim/dpi/hello/CMakeLists.txt new file mode 100644 index 0000000..b5dd59e --- /dev/null +++ b/examples/modelsim/dpi/hello/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.25) +project(hello_dpi CXX) + +add_library(hello_dpi SHARED + ./hello.cpp + ) + +target_compile_options(hello_dpi PRIVATE -m32) +target_link_options(hello_dpi PRIVATE -m32) diff --git a/examples/modelsim/dpi/hello/hello.cpp b/examples/modelsim/dpi/hello/hello.cpp new file mode 100644 index 0000000..01ff8ee --- /dev/null +++ b/examples/modelsim/dpi/hello/hello.cpp @@ -0,0 +1,7 @@ +#include + +extern "C" uint32_t hello(uint32_t data); +uint32_t hello(uint32_t data) +{ + return data + 10; +} diff --git a/examples/modelsim/dpi/tb.sv b/examples/modelsim/dpi/tb.sv new file mode 100644 index 0000000..0806bfe --- /dev/null +++ b/examples/modelsim/dpi/tb.sv @@ -0,0 +1,9 @@ +module tb; + + import "DPI-C" function int unsigned hello(input int unsigned data); + + initial begin + $display("From DPI-C 5 + 10 is: %d", hello(5)); + $finish(); + end +endmodule diff --git a/examples/modelsim/parallel/CMakeLists.txt b/examples/modelsim/parallel/CMakeLists.txt new file mode 100644 index 0000000..6f8fde9 --- /dev/null +++ b/examples/modelsim/parallel/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.25) +project(parallel_example NONE) + +include("../../../SoCMakeConfig.cmake") + +add_ip(tb + DESCRIPTION "Simple verilog testbench" + ) + +ip_sources(${IP} VERILOG + ${PROJECT_SOURCE_DIR}/tb.v + ) + +add_subdirectory(printer) + +foreach(cnt RANGE 0 32) + stupid_printer(${cnt}) + ip_link(${IP} vendor::lib_${cnt}::printer_${cnt}::0.0.1) +endforeach() + +modelsim(${IP} TARGET_PER_IP) + +help() diff --git a/examples/modelsim/parallel/printer/CMakeLists.txt b/examples/modelsim/parallel/printer/CMakeLists.txt new file mode 100644 index 0000000..9ca08ca --- /dev/null +++ b/examples/modelsim/parallel/printer/CMakeLists.txt @@ -0,0 +1,14 @@ + +function(stupid_printer NUM_TO_ADD) + add_ip(vendor::lib_${NUM_TO_ADD}::printer_${NUM_TO_ADD}::0.0.1 + DESCRIPTION "A stupid module that prints ${NUM_TO_ADD}") + + configure_file( + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/printer.v.in + ${CMAKE_BINARY_DIR}/printer_${NUM_TO_ADD}.v + @ONLY + ) + ip_sources(${IP} VERILOG + ${CMAKE_BINARY_DIR}/printer_${NUM_TO_ADD}.v + ) +endfunction() diff --git a/examples/modelsim/parallel/printer/printer.v.in b/examples/modelsim/parallel/printer/printer.v.in new file mode 100644 index 0000000..e92e317 --- /dev/null +++ b/examples/modelsim/parallel/printer/printer.v.in @@ -0,0 +1,5 @@ +module printer_@NUM_TO_ADD@; + initial begin + $display("NUM IS: %d", @NUM_TO_ADD@); + end +endmodule diff --git a/examples/modelsim/parallel/tb.v b/examples/modelsim/parallel/tb.v new file mode 100644 index 0000000..fb5a4c1 --- /dev/null +++ b/examples/modelsim/parallel/tb.v @@ -0,0 +1,41 @@ +module tb; + + printer_0 printer_0_i (); + printer_1 printer_1_i (); + printer_2 printer_2_i (); + printer_3 printer_3_i (); + printer_4 printer_4_i (); + printer_5 printer_5_i (); + printer_6 printer_6_i (); + printer_7 printer_7_i (); + printer_8 printer_8_i (); + printer_9 printer_9_i (); + printer_10 printer_10_i (); + printer_11 printer_11_i (); + printer_12 printer_12_i (); + printer_13 printer_13_i (); + printer_14 printer_14_i (); + printer_15 printer_15_i (); + printer_16 printer_16_i (); + printer_17 printer_17_i (); + printer_18 printer_18_i (); + printer_19 printer_19_i (); + printer_20 printer_20_i (); + printer_21 printer_21_i (); + printer_22 printer_22_i (); + printer_23 printer_23_i (); + printer_24 printer_24_i (); + printer_25 printer_25_i (); + printer_26 printer_26_i (); + printer_27 printer_27_i (); + printer_28 printer_28_i (); + printer_29 printer_29_i (); + printer_30 printer_30_i (); + printer_31 printer_31_i (); + printer_32 printer_32_i (); + + initial begin + $display("Hello world, from SoCMake build system\n"); + $finish(); + end + endmodule diff --git a/examples/modelsim/simple/CMakeLists.txt b/examples/modelsim/simple/CMakeLists.txt new file mode 100644 index 0000000..65a6342 --- /dev/null +++ b/examples/modelsim/simple/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.25) +project(example NONE) + +include("../../../SoCMakeConfig.cmake") + +add_ip(tb + DESCRIPTION "Simple verilog testbench" + ) + +ip_sources(${IP} VERILOG + ${PROJECT_SOURCE_DIR}/tb.v + ) + +add_subdirectory(adder) + +ip_link(${IP} adder) + +modelsim(${IP} TARGET_PER_IP) + +help() diff --git a/examples/modelsim/adder/CMakeLists.txt b/examples/modelsim/simple/adder/CMakeLists.txt similarity index 57% rename from examples/modelsim/adder/CMakeLists.txt rename to examples/modelsim/simple/adder/CMakeLists.txt index f394dac..307f212 100644 --- a/examples/modelsim/adder/CMakeLists.txt +++ b/examples/modelsim/simple/adder/CMakeLists.txt @@ -1,5 +1,6 @@ -add_ip(vendor::lib::adder::0.0.1) +add_ip(adder + DESCRIPTION "Just a simple adder") ip_sources(${IP} VHDL ${CMAKE_CURRENT_LIST_DIR}/adder.vhdl diff --git a/examples/modelsim/adder/adder.vhdl b/examples/modelsim/simple/adder/adder.vhdl similarity index 100% rename from examples/modelsim/adder/adder.vhdl rename to examples/modelsim/simple/adder/adder.vhdl diff --git a/examples/modelsim/tb.v b/examples/modelsim/simple/tb.v similarity index 100% rename from examples/modelsim/tb.v rename to examples/modelsim/simple/tb.v