2019-10-17 23:44:10 +00:00
######################################################################
#
# DESCRIPTION: CMake configuration file for Verilator
#
# Include it in your CMakeLists.txt using:
#
# find_package(verilate)
#
# This script adds a verilate function.
#
# add_executable(simulator <your-c-sources>)
# verilate(simulator SOURCES <your-hdl-sources>)
#
2020-03-21 15:24:24 +00:00
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
2019-10-17 23:44:10 +00:00
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
2020-03-21 15:24:24 +00:00
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
2019-10-17 23:44:10 +00:00
#
######################################################################
cmake_minimum_required ( VERSION 3.8 )
# Prefer VERILATOR_ROOT from environment
if ( DEFINED ENV{VERILATOR_ROOT} )
set ( VERILATOR_ROOT "$ENV{VERILATOR_ROOT}" CACHE PATH "VERILATOR_ROOT" )
endif ( )
set ( VERILATOR_ROOT "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "VERILATOR_ROOT" )
find_program ( VERILATOR_BIN NAMES verilator_bin verilator_bin.exe
H I N T S $ { V E R I L A T O R _ R O O T } / b i n E N V V E R I L A T O R _ R O O T
N O _ C M A K E _ P A T H N O _ C M A K E _ E N V I R O N M E N T _ P A T H N O _ C M A K E _ S Y S T E M _ P A T H )
if ( NOT VERILATOR_ROOT )
message ( FATAL_ERROR "VERILATOR_ROOT cannot be detected. Set it to the appropriate directory (e.g. /usr/share/verilator) as an environment variable or CMake define." )
endif ( )
if ( NOT VERILATOR_BIN )
message ( FATAL_ERROR "Cannot find verilator_bin excecutable." )
endif ( )
set ( verilator_FOUND 1 )
include ( CheckCXXSourceCompiles )
function ( _verilator_check_cxx_libraries LIBRARIES RESVAR )
# Check whether a particular link option creates a valid executable
set ( _VERILATOR_CHECK_CXX_LINK_OPTIONS_SRC "int main() {return 0;}\n" )
set ( CMAKE_REQUIRED_FLAGS )
set ( CMAKE_REQUIRED_DEFINITIONS )
set ( CMAKE_REQUIRED_INCLUDES )
set ( CMAKE_REQUIRED_LINK_OPTIONS )
set ( CMAKE_REQUIRED_LIBRARIES ${ LIBRARIES } )
set ( CMAKE_REQUIRED_QUIET )
check_cxx_source_compiles ( "${_VERILATOR_CHECK_CXX_LINK_OPTIONS_SRC}" "${RESVAR}" )
set ( "${RESVAR}" "${${RESVAR}}" PARENT_SCOPE )
endfunction ( )
# Check compiler flag support. Skip on MSVC, these are all GCC flags.
if ( NOT CMAKE_CXX_COMPILER_ID MATCHES MSVC )
if ( NOT DEFINED VERILATOR_CFLAGS OR NOT DEFINED VERILATOR_MT_CFLAGS )
include ( CheckCXXCompilerFlag )
foreach ( FLAG @CFG_CXX_FLAGS_CMAKE@ )
string ( MAKE_C_IDENTIFIER ${ FLAG } FLAGNAME )
check_cxx_compiler_flag ( ${ FLAG } ${ FLAGNAME } )
if ( ${ FLAGNAME } )
list ( APPEND VERILATOR_CFLAGS ${ FLAG } )
endif ( )
endforeach ( )
foreach ( FLAG @CFG_LDFLAGS_THREADS_CMAKE@ )
string ( MAKE_C_IDENTIFIER ${ FLAG } FLAGNAME )
_verilator_check_cxx_libraries ( "${FLAG}" ${ FLAGNAME } )
if ( ${ FLAGNAME } )
list ( APPEND VERILATOR_MT_CFLAGS ${ FLAG } )
endif ( )
endforeach ( )
endif ( )
endif ( )
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ T H R E A D E D
B R I E F _ D O C S " V e r i l a t o r m u l t i t h r e a d i n g e n a b l e d "
F U L L _ D O C S " V e r i l a t o r m u l t i t h r e a d i n g e n a b l e d "
)
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ C O V E R A G E
B R I E F _ D O C S " V e r i l a t o r c o v e r a g e e n a b l e d "
F U L L _ D O C S " V e r i l a t o r c o v e r a g e e n a b l e d "
)
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ T R A C E
B R I E F _ D O C S " V e r i l a t o r t r a c e e n a b l e d "
F U L L _ D O C S " V e r i l a t o r t r a c e e n a b l e d "
)
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ T R A C E _ V C D
B R I E F _ D O C S " V e r i l a t o r V C D t r a c e e n a b l e d "
F U L L _ D O C S " V e r i l a t o r V C D t r a c e e n a b l e d "
)
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ T R A C E _ F S T
B R I E F _ D O C S " V e r i l a t o r F S T t r a c e e n a b l e d "
F U L L _ D O C S " V e r i l a t o r F S T t r a c e e n a b l e d "
)
define_property ( TARGET
P R O P E R T Y V E R I L A T O R _ S Y S T E M C
B R I E F _ D O C S " V e r i l a t o r S y s t e m C e n a b l e d "
F U L L _ D O C S " V e r i l a t o r S y s t e m C e n a b l e d "
)
function ( verilate TARGET )
cmake_parse_arguments ( VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC"
" P R E F I X ; T O P _ M O D U L E ; T H R E A D S ; D I R E C T O R Y "
" S O U R C E S ; V E R I L A T O R _ A R G S ; I N C L U D E _ D I R S ; O P T _ S L O W ; O P T _ F A S T "
$ { A R G N } )
if ( NOT VERILATE_SOURCES )
message ( FATAL_ERROR "Need at least one source" )
endif ( )
if ( NOT VERILATE_PREFIX )
list ( GET VERILATE_SOURCES 0 TOPSRC )
get_filename_component ( _SRC_NAME ${ TOPSRC } NAME_WE )
set ( VERILATE_PREFIX V ${ _SRC_NAME } )
endif ( )
if ( VERILATE_TOP_MODULE )
list ( APPEND VERILATOR_ARGS --top-module ${ VERILATE_TOP_MODULE } )
endif ( )
if ( VERILATE_THREADS )
list ( APPEND VERILATOR_ARGS --threads ${ VERILATE_THREADS } )
endif ( )
if ( VERILATE_COVERAGE )
list ( APPEND VERILATOR_ARGS --coverage )
endif ( )
if ( VERILATE_TRACE AND VERILATE_TRACE_FST )
message ( FATAL_ERROR "Cannot have both TRACE and TRACE_FST" )
endif ( )
if ( VERILATE_TRACE )
list ( APPEND VERILATOR_ARGS --trace )
endif ( )
if ( VERILATE_TRACE_FST )
list ( APPEND VERILATOR_ARGS --trace-fst )
endif ( )
if ( VERILATE_SYSTEMC )
list ( APPEND VERILATOR_ARGS --sc )
else ( )
list ( APPEND VERILATOR_ARGS --cc )
endif ( )
foreach ( INC ${ VERILATE_INCLUDE_DIRS } )
list ( APPEND VERILATOR_ARGS -y "${INC}" )
endforeach ( )
string ( TOLOWER ${ CMAKE_CXX_COMPILER_ID } COMPILER )
2020-04-23 11:14:20 +00:00
if ( COMPILER STREQUAL "appleclang" )
set ( COMPILER clang )
elseif ( NOT COMPILER MATCHES "^msvc$|^clang$" )
2019-10-17 23:44:10 +00:00
set ( COMPILER gcc )
endif ( )
get_target_property ( BINARY_DIR "${TARGET}" BINARY_DIR )
get_target_property ( TARGET_NAME "${TARGET}" NAME )
set ( VDIR "${BINARY_DIR}/CMakeFiles/${TARGET_NAME}.dir/${VERILATE_PREFIX}.dir" )
if ( VERILATE_DIRECTORY )
set ( VDIR "${VERILATE_DIRECTORY}" )
endif ( )
file ( MAKE_DIRECTORY ${ VDIR } )
set ( VERILATOR_COMMAND "${VERILATOR_BIN}" --compiler ${ COMPILER }
- - p r e f i x $ { V E R I L A T E _ P R E F I X } - - M d i r $ { V D I R } - - m a k e c m a k e
$ { V E R I L A T O R _ A R G S } $ { V E R I L A T E _ V E R I L A T O R _ A R G S }
$ { V E R I L A T E _ S O U R C E S } )
set ( VARGS_FILE "${VDIR}/verilator_args.txt" )
set ( VCMAKE "${VDIR}/${VERILATE_PREFIX}.cmake" )
set ( VCMAKE_COPY "${VDIR}/${VERILATE_PREFIX}_copy.cmake" )
if ( NOT EXISTS "${VARGS_FILE}" OR NOT EXISTS "${VCMAKE_COPY}" )
set ( VERILATOR_OUTDATED ON )
else ( )
file ( READ "${VARGS_FILE}" PREVIOUS_VERILATOR_COMMAND )
if ( NOT VERILATOR_COMMAND STREQUAL PREVIOUS_VERILATOR_COMMAND )
set ( VERILATOR_OUTDATED ON )
endif ( )
endif ( )
if ( VERILATOR_OUTDATED )
message ( STATUS "Executing Verilator..." )
execute_process (
C O M M A N D $ { V E R I L A T O R _ C O M M A N D }
W O R K I N G _ D I R E C T O R Y " $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R } "
R E S U L T _ V A R I A B L E _ V E R I L A T O R _ R C
O U T P U T _ V A R I A B L E _ V E R I L A T O R _ O U T P U T
E R R O R _ V A R I A B L E _ V E R I L A T O R _ O U T P U T )
if ( _VERILATOR_RC )
string ( REPLACE ";" " " VERILATOR_COMMAND_READABLE "${VERILATOR_COMMAND}" )
message ( "Verilator command: \" ${ VERILATOR_COMMAND_READABLE } \"")
message ( "Output:\n${_VERILATOR_OUTPUT}" )
message ( FATAL_ERROR "Verilator command failed (return code=${_VERILATOR_RC})" )
endif ( )
execute_process ( COMMAND "${CMAKE_COMMAND}" -E copy "${VCMAKE}" "${VCMAKE_COPY}" )
endif ( )
file ( WRITE "${VARGS_FILE}" "${VERILATOR_COMMAND}" )
include ( "${VCMAKE_COPY}" )
set ( GENERATED_C_SOURCES ${ ${VERILATE_PREFIX } _CLASSES_FAST}
$ { $ { V E R I L A T E _ P R E F I X } _ C L A S S E S _ S L O W }
$ { $ { V E R I L A T E _ P R E F I X } _ S U P P O R T _ F A S T }
$ { $ { V E R I L A T E _ P R E F I X } _ S U P P O R T _ S L O W } )
foreach ( GENERATED_C_SOURCE ${ GENERATED_C_SOURCES } )
get_filename_component ( C_OUTPUT_NAME_WE "${GENERATED_C_SOURCE}" NAME_WE )
if ( C_OUTPUT_NAME_WE MATCHES ".*Trace.*" )
continue ( )
endif ( )
list ( APPEND GENERATED_H_SOURCES "${VDIR}/${C_OUTPUT_NAME_WE}.h" )
endforeach ( )
set ( GENERATED_SOURCES ${ GENERATED_C_SOURCES } ${ GENERATED_H_SOURCES } )
add_custom_command ( OUTPUT ${ GENERATED_SOURCES } "${VCMAKE}"
C O M M A N D $ { V E R I L A T O R _ C O M M A N D }
W O R K I N G _ D I R E C T O R Y " $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R } "
D E P E N D S " $ { V E R I L A T O R _ B I N } " $ { $ { V E R I L A T E _ P R E F I X } _ D E P S } V E R B A T I M )
# Reconfigure if file list has changed
# (check contents rather than modified time to avoid unnecessary reconfiguration)
add_custom_command ( OUTPUT "${VCMAKE_COPY}"
C O M M A N D " $ { C M A K E _ C O M M A N D } " - E c o p y _ i f _ d i f f e r e n t
" $ { V C M A K E } " " $ { V C M A K E _ C O P Y } "
D E P E N D S " $ { V C M A K E } " V E R B A T I M )
if ( ${ VERILATE_PREFIX } _THREADS )
# If any verilate() call specifies THREADS, define VL_THREADED in the final build
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_THREADED ON )
endif ( )
if ( ${ VERILATE_PREFIX } _COVERAGE )
# If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_COVERAGE ON )
endif ( )
if ( ${ VERILATE_PREFIX } _TRACE_VCD )
# If any verilate() call specifies TRACE, define VM_TRACE in the final build
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_TRACE ON )
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_TRACE_VCD ON )
endif ( )
if ( ${ VERILATE_PREFIX } _TRACE_FST )
# If any verilate() call specifies TRACE_FST, define VM_TRACE_FST in the final build
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_TRACE ON )
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_TRACE_FST ON )
endif ( )
if ( ${ VERILATE_PREFIX } _SC )
# If any verilate() call specifies SYSTEMC, define VM_SC in the final build
set_property ( TARGET ${ TARGET } PROPERTY VERILATOR_SYSTEMC ON )
endif ( )
# Add the compile flags only on Verilated sources
target_include_directories ( ${ TARGET } PUBLIC ${ VDIR } )
target_sources ( ${ TARGET } PRIVATE ${ GENERATED_SOURCES } "${VCMAKE_COPY}"
$ { $ { V E R I L A T E _ P R E F I X } _ G L O B A L }
$ { $ { V E R I L A T E _ P R E F I X } _ U S E R _ C L A S S E S } )
foreach ( _VSOURCE ${ VERILATE_SOURCES } ${ ${VERILATE_PREFIX } _DEPS} )
get_filename_component ( _VSOURCE "${_VSOURCE}" ABSOLUTE BASE_DIR )
list ( APPEND VHD_SOURCES "${_VSOURCE}" )
endforeach ( )
target_sources ( ${ TARGET } PRIVATE ${ VHD_SOURCES } )
# Add the compile flags only on Verilated sources
foreach ( VSLOW ${ ${VERILATE_PREFIX } _CLASSES_SLOW} ${ ${VERILATE_PREFIX } _SUPPORT_SLOW} )
foreach ( OPT_SLOW ${ VERILATE_OPT_SLOW } ${ ${VERILATE_PREFIX } _USER_CFLAGS} )
set_property ( SOURCE "${VSLOW}" APPEND_STRING PROPERTY COMPILE_FLAGS " ${OPT_SLOW}" )
endforeach ( )
endforeach ( )
foreach ( VFAST ${ ${VERILATE_PREFIX } _CLASSES_FAST} ${ ${VERILATE_PREFIX } _SUPPORT_FAST} )
foreach ( OPT_FAST ${ VERILATE_OPT_FAST } ${ ${VERILATE_PREFIX } _USER_CFLAGS} )
set_property ( SOURCE "${VFAST}" APPEND_STRING PROPERTY COMPILE_FLAGS " ${OPT_FAST}" )
endforeach ( )
endforeach ( )
target_include_directories ( ${ TARGET } PUBLIC "${VERILATOR_ROOT}/include"
" $ { V E R I L A T O R _ R O O T } / i n c l u d e / v l t s t d " )
target_compile_definitions ( ${ TARGET } PRIVATE
V M _ C O V E R A G E = $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ C O V E R A G E > >
V M _ S C = $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ S Y S T E M C > >
$ < $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ T H R E A D E D > > : V L _ T H R E A D E D >
V M _ T R A C E = $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ T R A C E > >
V M _ T R A C E _ V C D = $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ T R A C E _ V C D > >
V M _ T R A C E _ F S T = $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ T R A C E _ F S T > >
)
target_link_libraries ( ${ TARGET } PUBLIC
$ { $ { V E R I L A T E _ P R E F I X } _ U S E R _ L D L I B S }
" $ < $ < B O O L : $ < T A R G E T _ P R O P E R T Y : V E R I L A T O R _ T H R E A D E D > > : $ { V E R I L A T O R _ M T _ C F L A G S } > "
)
# SystemC requires the C++ version to match the library version, avoid setting anything here
set ( GEN_THREADED $< BOOL:$<TARGET_PROPERTY:VERILATOR_THREADED > > )
set ( GEN_SYSTEMC $< BOOL:$<TARGET_PROPERTY:VERILATOR_SYSTEMC > > )
target_compile_features ( ${ TARGET } PRIVATE
$ < $ < A N D : $ { G E N _ T H R E A D E D } , $ < N O T : $ { G E N _ S Y S T E M C } > > : c x x _ s t d _ 1 1 >
)
endfunction ( )
function ( _verilator_find_systemc )
if ( NOT TARGET Verilator::systemc )
# Find SystemC include file "systemc.h" in the following order:
# 1. SYSTEMC_INCLUDE (environment) variable
# 2. SYSTEMC_ROOT (environment) variable
# 3. SYSTEMC (environment) variable
# 4. Use CMake module provided by SystemC installation
# (eventually requires CMAKE_PREFIX_PATH set)
find_path ( SYSTEMC_INCLUDEDIR NAMES systemc.h
H I N T S " $ { S Y S T E M C _ I N C L U D E } " E N V S Y S T E M C _ I N C L U D E )
find_path ( SYSTEMC_INCLUDEDIR NAMES systemc.h
H I N T S " $ { S Y S T E M C _ R O O T } " E N V S Y S T E M C _ R O O T
P A T H _ S U F F I X E S i n c l u d e )
find_path ( SYSTEMC_INCLUDEDIR NAMES systemc.h
H I N T S " $ { S Y S T E M C } " E N V S Y S T E M C
P A T H _ S U F F I X E S i n c l u d e )
# Find SystemC library in the following order:
# 1. SYSTEMC_LIBDIR (environment) variable
# 2. SYSTEMC_ROOT (environment) variable
# 3. SYSTEMC (environment) variable
# 4. Use CMake module provided by SystemC installation
# (eventually requires CMAKE_PREFIX_PATH set)
# Find SystemC using include and library paths
find_library ( SYSTEMC_LIBRARY NAMES systemc
H I N T S " $ { S Y S T E M C _ L I B D I R } " E N V S Y S T E M C _ L I B D I R )
find_library ( SYSTEMC_LIBRARY NAMES systemc
H I N T S " $ { S Y S T E M C _ R O O T } " E N V S Y S T E M C _ R O O T
P A T H _ S U F F I X E S l i b )
find_library ( SYSTEMC_LIBRARY NAMES systemc
H I N T S " $ { S Y S T E M C } " E N V S Y S T E M C
P A T H _ S U F F I X E S l i b )
if ( SYSTEMC_INCLUDEDIR AND SYSTEMC_LIBRARY )
add_library ( Verilator::systemc INTERFACE IMPORTED )
set_target_properties ( Verilator::systemc
P R O P E R T I E S
I N T E R F A C E _ I N C L U D E _ D I R E C T O R I E S " $ { S Y S T E M C _ I N C L U D E D I R } "
I N T E R F A C E _ L I N K _ L I B R A R I E S " $ { S Y S T E M C _ L I B R A R Y } " )
return ( )
endif ( )
find_package ( SystemCLanguage QUIET )
if ( SystemCLanguage_FOUND )
add_library ( Verilator::systemc INTERFACE IMPORTED )
set_target_properties ( Verilator::systemc
P R O P E R T I E S
I N T E R F A C E _ L I N K _ L I B R A R I E S " S y s t e m C : : s y s t e m c " )
return ( )
endif ( )
message ( "SystemC not found. This can be fixed by doing either of the following steps:" )
message ( "- set the SYSTEMC_INCLUDE and SYSTEMC_LIBDIR (environment) variables; or" )
message ( "- set SYSTEMC_ROOT (environment) variable; or" )
message ( "- set SYSTEMC (environment) variable; or" )
message ( "- use the CMake module of your SystemC installation (may require CMAKE_PREFIX_PATH)" )
message ( FATAL_ERROR "SystemC not found" )
endif ( )
endfunction ( )
function ( verilator_link_systemc TARGET )
_verilator_find_systemc ( )
target_link_libraries ( "${TARGET}" PUBLIC Verilator::systemc )
target_compile_options ( ${ TARGET } PRIVATE $ENV{ SYSTEMC_CXX_FLAGS } ${ SYSTEMC_CXX_FLAGS } )
endfunction ( )
function ( verilator_generate_key OUTPUT_VARIABLE )
execute_process ( COMMAND ${ VERILATOR_BIN } --generate-key
O U T P U T _ V A R I A B L E K E Y _ V A L
R E S U L T _ V A R I A B L E K E Y _ R E T )
if ( KEY_RET )
message ( FATAL_ERROR "verilator --generate-key failed" )
endif ( )
string ( STRIP ${ KEY_VAL } KEY_VAL )
set ( ${ OUTPUT_VARIABLE } ${ KEY_VAL } PARENT_SCOPE )
endfunction ( )