Skip to content

Commit

Permalink
Refactor GHDL support, add simple VHDL simulation example
Browse files Browse the repository at this point in the history
  • Loading branch information
Risto97 committed Dec 23, 2024
1 parent 5913133 commit 9c091fb
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 86 deletions.
9 changes: 3 additions & 6 deletions cmake/sim/cadence/xcelium.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ function(xcelium IP_LIB)
# endif()

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

if(ARG_XMVLOG_ARGS)
Expand Down Expand Up @@ -125,8 +124,7 @@ function(__xcelium_compile_lib IP_LIB)
# endif()

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

# if(NOT ARG_OUTDIR)
Expand Down Expand Up @@ -216,8 +214,7 @@ function(__xcelium_compile_lib IP_LIB)
${IP_LIB}_xcelium_complib
DEPENDS ${STAMP_FILE} ${STAMP_FILE_VHDL} ${IP_LIB}
)
set_property(TARGET ${IP_LIB}_xcelium_complib PROPERTY
DESCRIPTION "Compile VHDL, SV, and Verilog files for ${IP_LIB} with xcelium in library ${LIBRARY}")
set_property(TARGET ${IP_LIB}_xcelium_complib PROPERTY DESCRIPTION ${DESCRIPTION})
endif()

# set(__XCELIUM_IP_LIB_DIR ${OUTDIR} PARENT_SCOPE)
Expand Down
237 changes: 162 additions & 75 deletions cmake/sim/ghdl/ghdl.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
include_guard(GLOBAL)

function(__ghdl_get_standard_arg OUTVAR)
set(SUPPORTED_VHDL_STANDARDS 87 93c 93 00 02 08)
if(ARGN)
if(NOT ${ARGN} IN_LIST SUPPORTED_VHDL_STANDARDS)
message(FATAL_ERROR "VHDL standard not supported ${ARGN}, supported standards: ${ARGN}")
endif()
set(${OUTVAR} ${ARGN} PARENT_SCOPE)
else()
set(${OUTVAR} 93 PARENT_SCOPE)
endif()
endfunction()

function(ghdl IP_LIB)
cmake_parse_arguments(ARG "" "OUTDIR;TOP_MODULE;EXECUTABLE;STANDARD" "" ${ARGN})
cmake_parse_arguments(ARG "TARGET_PER_IP;NO_RUN_TARGET;" "OUTDIR;TOP_MODULE;EXECUTABLE_NAME;STANDARD" "ANALYZE_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 @@ -12,105 +24,180 @@ function(ghdl IP_LIB)
get_target_property(BINARY_DIR ${IP_LIB} BINARY_DIR)

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

if(ARG_TOP_MODULE)
set(ARG_TOP_MODULE ${ARG_TOP_MODULE})
else()
# get_target_property(LIBRARY ${IP_LIB} LIBRARY)
# if(NOT LIBRARY)
set(LIBRARY work)
# endif()

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

set(SUPPORTED_VHDL_STANDARDS 87 93c 93 00 02 08)
if(ARG_STANDARD)
if(${ARG_STANDARD} IN_LIST SUPPORTED_VHDL_STANDARDS)
else()
message(FATAL_ERROR "VHDL standard not supported ${ARG_STANDARD}, supported standards: ${ARG_STANDARD}")
endif()
set(ARG_STANDARD --std=${ARG_STANDARD})
else()
set(ARG_STANDARD --std=93)
__ghdl_get_standard_arg(STANDARD ${ARG_STANDARD})

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

if(NOT ARG_EXECUTABLE)
set(ARG_EXECUTABLE "${OUTDIR}/${IP_LIB}_ghdl_tb")
if(NOT ARG_EXECUTABLE_NAME)
set(ARG_EXECUTABLE_NAME "${IP_LIB}_ghdl_exec")
endif()
get_filename_component(ARG_EXECUTABLE ${ARG_EXECUTABLE} ABSOLUTE)
set(SIM_EXEC_PATH "${OUTDIR}/${ARG_EXECUTABLE_NAME}")

get_ip_sources(VHDL_SOURCES ${IP_LIB} VHDL)
list(PREPEND SOURCES ${VHDL_SOURCES})
get_ip_links(IPS_LIST ${IP_LIB})

get_ip_include_directories(VHDL_INCLUDE_DIRS ${IP_LIB} VHDL)
set(INC_DIRS ${VHDL_INCLUDE_DIRS})
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()
set(list_comp_libs ${IP_LIB})
unset(__no_deps_arg)
endif()

foreach(dir ${INC_DIRS})
list(APPEND ARG_INCDIRS -P${dir})
##### GHDL Analyze

unset(__comp_tgts)
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
__ghdl_compile_lib(${ip} ${__no_deps_arg}
OUTDIR ${OUTDIR}
STANDARD ${STANDARD}
${ARG_ANALYZE_ARGS}
)
list(APPEND __comp_tgts ${ip}_ghdl_complib)
endif()
endforeach()

get_ip_compile_definitions(COMP_DEFS ${IP_LIB} VHDL)
foreach(def ${COMP_DEFS})
list(APPEND CMP_DEFS_ARG -D${def})
endforeach()
##### GHDL Elaborate
if(NOT TARGET ${IP_LIB}_ghdl)
get_ip_sources(VHDL_SOURCES ${IP_LIB} VHDL)
set(__ghdl_elab_cmd ghdl elaborate
--std=${STANDARD}
-fsynopsys
-o ${SIM_EXEC_PATH}
${ARG_ELABORATE_ARGS}
# -P${OUTDIR}
${__lib_args}
${LIBRARY}.${ARG_TOP_MODULE}
)

### Clean files
# * For elaborate "e~${ARG_EXECUTABLE_NAME}.o" and executable gets created
set(__clean_files "${OUTDIR}/e~${ARG_EXECUTABLE_NAME}.o")

set(DESCRIPTION "Compile testbench ${IP_LIB} with ${CMAKE_CURRENT_FUNCTION}")
set(STAMP_FILE "${BINARY_DIR}/${IP_LIB}_ghdl.stamp")
add_custom_command(
OUTPUT ${SIM_EXEC_PATH} ${STAMP_FILE}
COMMAND ${__ghdl_elab_cmd}
COMMAND touch ${STAMP_FILE}
BYPRODUCTS ${__clean_files}
WORKING_DIRECTORY ${OUTDIR}
DEPENDS ${__comp_tgts} ${VHDL_SOURCES}
COMMENT ${DESCRIPTION}
)

find_program(GHDL_EXECUTABLE ghdl
HINTS ${GHDL_HOME}/bin/ $ENV{GHDL_HOME}/bin/
PATHS ${GHDL_EXECUTABLE} $ENV{GHDL_EXECUTABLE}
add_custom_target(${IP_LIB}_ghdl
DEPENDS ${STAMP_FILE} ${IP_LIB}
)
set_property(TARGET ${IP_LIB}_ghdl PROPERTY DESCRIPTION ${DESCRIPTION})
endif()

set(__ghdl_run_cmd ${SIM_EXEC_PATH} ${ARG_RUN_ARGS})
if(NOT ARG_NO_RUN_TARGET)
if(NOT ARG_RUN_TARGET_NAME)
set(ARG_RUN_TARGET_NAME run_${IP_LIB}_${CMAKE_CURRENT_FUNCTION})
endif()
set(DESCRIPTION "Run simulation on ${IP_LIB} with ${CMAKE_CURRENT_FUNCTION}")
add_custom_target(${ARG_RUN_TARGET_NAME}
COMMAND ${__ghdl_run_cmd}
COMMENT ${DESCRIPTION}
WORKING_DIRECTORY ${OUTDIR}
DEPENDS ${IP_LIB}_ghdl
)
set_property(TARGET ${ARG_RUN_TARGET_NAME} PROPERTY DESCRIPTION ${DESCRIPTION})
endif()
set(SIM_RUN_CMD ${__ghdl_run_cmd} PARENT_SCOPE)

endfunction()

get_target_property(IPS ${IP_LIB} FLAT_GRAPH)
function(__ghdl_compile_lib IP_LIB)
cmake_parse_arguments(ARG "NO_DEPS" "OUTDIR;STANDARD" "ANALYZE_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}_ghdl)
else()
set(OUTDIR ${ARG_OUTDIR})
endif()
file(MAKE_DIRECTORY ${OUTDIR})

if(ARG_NO_DEPS)
set(ARG_NO_DEPS NO_DEPS)
else()
unset(ARG_NO_DEPS)
endif()

unset(_ghdl_analyze_commands)
foreach(_ip ${IPS})
get_target_property(_lib ${_ip} LIBRARY)
get_target_property(_lib_sources ${_ip} VHDL_SOURCES)
__ghdl_get_standard_arg(STANDARD ${ARG_STANDARD})

list(APPEND _ghdl_analyze_commands
COMMAND ${GHDL_EXECUTABLE} analyze
--work=${_lib}
# VHDL files and arguments
get_ip_sources(VHDL_SOURCES ${IP_LIB} VHDL ${ARG_NO_DEPS})
set(__ghdl_analyze_cmd COMMAND ghdl analyze
--std=${STANDARD}
-fsynopsys
${ARG_ANALYZE_ARGS}
--work=${LIBRARY}
--workdir=${OUTDIR}
${ARG_STANDARD}
-P${OUTDIR}
${_lib_sources}
${VHDL_SOURCES}
)
endforeach()
get_target_property(WORK_LIB ${IP_LIB} LIBRARY)

# TODO split custom_command into analysis commands per IP block, so only analysis of a IP block is done for the files changed of the given IP block, this should speed up for big designs
set(STAMP_FILE "${BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}.stamp")
add_custom_command(
OUTPUT ${ARG_EXECUTABLE} ${STAMP_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTDIR}
${_ghdl_analyze_commands}
COMMAND ${GHDL_EXECUTABLE} elaborate
-P${OUTDIR}
-o ${ARG_EXECUTABLE}
--work=${WORK_LIB}
--workdir=${OUTDIR}
${ARG_STANDARD}
${ARG_TOP_MODULE}
COMMAND touch ${STAMP_FILE}
DEPENDS ${SOURCES}
COMMENT "Running ${CMAKE_CURRENT_FUNCTION} on ${IP_LIB}"
)

add_custom_target(
${IP_LIB}_${CMAKE_CURRENT_FUNCTION}
DEPENDS ${ARG_EXECUTABLE} ${IP_LIB} ${STAMP_FILE}
### Clean files:
# * All .o files from vhdl sources
unset(__clean_files)
foreach(source ${VHDL_SOURCES})
get_filename_component(source_basename ${source} NAME_WLE)
list(APPEND __clean_files "${OUTDIR}/${source_basename}.o")
endforeach()
list(APPEND __clean_files "${OUTDIR}/${LIBRARY}-obj${STANDARD}.cf")

if(NOT TARGET ${IP_LIB}_ghdl_complib)
set(DESCRIPTION "Compile VHDL for ${IP_LIB} with ghdl in library ${LIBRARY}")
set(STAMP_FILE "${BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}.stamp")
add_custom_command(
OUTPUT ${STAMP_FILE}
${__ghdl_analyze_cmd}
COMMAND touch ${STAMP_FILE}
WORKING_DIRECTORY ${OUTDIR}
BYPRODUCTS ${__clean_files}
DEPENDS ${VHDL_SOURCES}
COMMENT ${DESCRIPTION}
)

get_filename_component(EXEC_FN ${ARG_EXECUTABLE} NAME)
get_filename_component(EXEC_DIR ${ARG_EXECUTABLE} DIRECTORY)

set_property(
TARGET ${IP_LIB}_${CMAKE_CURRENT_FUNCTION}
APPEND PROPERTY ADDITIONAL_CLEAN_FILES
${OUTDIR}
${ARG_EXECUTABLE}
${EXEC_DIR}/e~${EXEC_FN}.o
add_custom_target(
${IP_LIB}_ghdl_complib
DEPENDS ${STAMP_FILE} ${IP_LIB}
)

# add_dependencies(${IP_LIB} ${IP_LIB}_${CMAKE_CURRENT_FUNCTION})
set_property(TARGET ${IP_LIB}_ghdl_complib PROPERTY DESCRIPTION ${DESCRIPTION})
endif()

endfunction()
8 changes: 3 additions & 5 deletions cmake/sim/synopsys/vcs.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include_guard(GLOBAL)

function(vcs IP_LIB)
cmake_parse_arguments(ARG "TARGET_PER_IP;NO_RUN_TARGET;GUI" "EXECUTABLE_NAME;RUN_TARGET_NAME" "VLOGAN_ARGS;VHDLAN_ARGS;VCS_ARGS;RUN_ARGS" ${ARGN})
cmake_parse_arguments(ARG "TARGET_PER_IP;NO_RUN_TARGET;GUI" "OUTDIR;EXECUTABLE_NAME;RUN_TARGET_NAME" "VLOGAN_ARGS;VHDLAN_ARGS;VCS_ARGS;RUN_ARGS" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
endif()
Expand All @@ -24,8 +24,7 @@ function(vcs IP_LIB)
# endif()

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

if(ARG_VLOGAN_ARGS)
Expand Down Expand Up @@ -145,8 +144,7 @@ function(__vcs_compile_lib IP_LIB)
file(MAKE_DIRECTORY ${OUTDIR})

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

if(ARG_NO_DEPS)
Expand Down
36 changes: 36 additions & 0 deletions examples/simple_vhdl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.25)
project(simple_mixed_language NONE)

include("../../SoCMakeConfig.cmake")

option_enum(SIMULATOR "Which simulator to use" "ghdl;questa;modelsim;xcelium;vcs;all" "ghdl")
if(SIMULATOR STREQUAL "all")
set(ALL_SIMS TRUE)
endif()

add_ip(tb
DESCRIPTION "Simple verilog testbench")

ip_sources(${IP} VHDL
tb.vhdl)

add_subdirectory(adder)
ip_link(${IP} adder)

if(SIMULATOR STREQUAL "questa" OR SIMULATOR STREQUAL "modelsim" OR ALL_SIMS)
modelsim(${IP})
endif()

if(SIMULATOR STREQUAL "xcelium" OR ALL_SIMS)
xcelium(${IP} XMVHDL_ARGS -V200x)
endif()

if(SIMULATOR STREQUAL "vcs" OR ALL_SIMS)
vcs(${IP})
endif()

if(SIMULATOR STREQUAL "ghdl" OR ALL_SIMS)
ghdl(${IP})
endif()

help()
7 changes: 7 additions & 0 deletions examples/simple_vhdl/adder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

add_ip(adder
DESCRIPTION "Just a simple adder")

ip_sources(${IP} VHDL
adder.vhdl
)
16 changes: 16 additions & 0 deletions examples/simple_vhdl/adder/adder.vhdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity adder is
Port ( NUM1 : in STD_LOGIC_VECTOR (4 downto 0) := "00000";
NUM2 : in STD_LOGIC_VECTOR (4 downto 0) := "00000";
SUM : out STD_LOGIC_VECTOR (4 downto 0));
end adder;

architecture Behavioral of adder is
begin

SUM <= NUM1 + NUM2;

end Behavioral;
Loading

0 comments on commit 9c091fb

Please sign in to comment.