diff --git a/.gitignore b/.gitignore index fdbb3d1d1..725173409 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,6 @@ verilator.txt verilator_bin* verilator_coverage_bin* verilator.pc +verilator-config.cmake +verilator-config-version.cmake **/obj_dir/* diff --git a/Changes b/Changes index 781e6d37e..7a00339da 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! ** Add --protect-lib, bug1490. [Todd Strader] +** Add cmake support, bug1363. [Patrick Stewart] + *** Examples have been renamed. *** Add --protect-ids to obscure information in objects, bug1521. [Todd Strader] diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index 57338db2e..e14400721 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -15,6 +15,7 @@ .*\.vcd .*\.1 \.travis\.yml +/build/ /obj_dir/ /obj_dbg/ /obj_nc/ @@ -39,6 +40,8 @@ config.cache$ config.status$ verilator\.log verilator\.tex +verilator-config.cmake$ +verilator-config-version.cmake$ verilator.pc$ verilator_bin.* verilator_coverage_bin.* diff --git a/Makefile.in b/Makefile.in index 5ce1c1ab0..e129bd627 100644 --- a/Makefile.in +++ b/Makefile.in @@ -104,6 +104,11 @@ PACKAGE_VERSION = @PACKAGE_VERSION@ SHELL = /bin/sh SUBDIRS = src test_regress \ + examples/cmake_hello_c \ + examples/cmake_hello_sc \ + examples/cmake_tracing_c \ + examples/cmake_tracing_sc \ + examples/cmake_protect_lib \ examples/make_hello_c \ examples/make_hello_sc \ examples/make_tracing_c \ @@ -122,6 +127,8 @@ DISTFILES_INC = $(INFOS) .gitignore \ Changes \ LICENSE \ MANIFEST.SKIP \ + verilator-config.cmake.in \ + verilator-config-version.cmake.in \ bin/verilator \ bin/verilator_coverage \ bin/verilator_difftree \ @@ -151,8 +158,14 @@ DISTFILES_INC = $(INFOS) .gitignore \ src/*.pl src/*.pod \ examples/*/.*ignore examples/*/Makefile* \ examples/*/*.[chv]* examples/*/*.pl \ + examples/*/CMakeLists.txt \ test_*/.*ignore test_*/Makefile* test_*/*.cpp \ test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \ + test_regress/*.pl \ + test_regress/Makefile \ + test_regress/Makefile_obj \ + test_regress/input.vc \ + test_regress/CMakeLists.txt \ test_regress/t/t*/*.sv* \ test_regress/t/t*/*.v* \ test_regress/t/t*/*/*.sv* \ @@ -302,6 +315,7 @@ VL_INST_INC_SRCDIR_FILES = \ VL_INST_DATA_SRCDIR_FILES = \ examples/*/*.[chv]* examples/*/Makefile* \ + examples/*/CMakeLists.txt installbin: $(MKINSTALLDIRS) $(DESTDIR)$(bindir) @@ -338,12 +352,19 @@ installdata: $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_tracing_sc $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_protect_lib + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_hello_c + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_hello_sc + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc + $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib cd $(srcdir) \ ; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \ $(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \ done $(MKINSTALLDIRS) $(DESTDIR)$(pkgconfigdir) $(INSTALL_DATA) verilator.pc $(DESTDIR)$(pkgconfigdir) + $(INSTALL_DATA) verilator-config.cmake $(DESTDIR)$(pkgdatadir) + $(INSTALL_DATA) verilator-config-version.cmake $(DESTDIR)$(pkgdatadir) # We don't trust rm -rf, so rmdir instead as it will fail if user put in other files uninstall: @@ -354,6 +375,8 @@ uninstall: -cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_SRCDIR_FILES) -cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_DATA_SRCDIR_FILES) -rm $(DESTDIR)$(pkgconfigdir)/verilator.pc + -rm $(DESTDIR)$(pkgdatadir)/verilator-config.cmake + -rm $(DESTDIR)$(pkgdatadir)/verilator-config-version.cmake -rmdir $(DESTDIR)$(pkgdatadir)/bin -rmdir $(DESTDIR)$(pkgdatadir)/include/gtkwave -rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd @@ -363,7 +386,13 @@ uninstall: -rmdir $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c -rmdir $(DESTDIR)$(pkgdatadir)/examples/make_tracing_sc -rmdir $(DESTDIR)$(pkgdatadir)/examples/make_protect_lib + -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_hello_c + -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_hello_sc + -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c + -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc + -rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib -rmdir $(DESTDIR)$(pkgdatadir)/examples + -rmdir $(DESTDIR)$(pkgdatadir)/cmake -rmdir $(DESTDIR)$(pkgdatadir) -rmdir $(DESTDIR)$(pkgconfigdir) diff --git a/README.pod b/README.pod index 3587f61a7..a0b31384b 100644 --- a/README.pod +++ b/README.pod @@ -257,6 +257,11 @@ The directories in the package directory are as follows: examples/make_tracing_c => Example GNU-make Verilog->C++ with tracing examples/make_tracing_sc => Example GNU-make Verilog->SystemC with tracing examples/make_protect_lib => Example using --protect-lib + examples/cmake_hello_c => Example building make_hello_c with CMake + examples/cmake_hello_sc => Example building make_hello_sc with CMake + examples/cmake_tracing_c => Example building make_tracing_c with CMake + examples/cmake_tracing_sc => Example building make_tracing_sc with CMake + examples/cmake_protect_lib => Example building make_protect_lib with CMake include/ => Files that should be in your -I compiler path include/verilated*.cpp => Global routines to link into your simulator include/verilated*.h => Global headers diff --git a/bin/verilator b/bin/verilator index fa3ecda1f..06a43c149 100755 --- a/bin/verilator +++ b/bin/verilator @@ -283,6 +283,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information. --cc Create C++ output --cdc Clock domain crossing analysis --clk <signal-name> Mark specified signal as clock + --make <make-system> Generate scripts for specified make system --compiler <compiler-name> Tune for specified C++ compiler --converge-limit <loops> Tune convergence settle time --coverage Enable all coverage @@ -574,6 +575,13 @@ If clock signals are assigned to vectors and then later used individually, Verilator will attempt to decompose the vector and connect the single-bit clock signals directly. This should be transparent to the user. +=item --make I<make-system> + +Generates a script for the specified make system. + +Supported make systems are gmake and cmake. Both can be specified. +If no make system is specified, gmake is assumed. + =item --compiler I<compiler-name> Enables tunings and workarounds for the specified C++ compiler. @@ -1944,9 +1952,15 @@ All output files are placed in the output directory name specified with the Verilator creates the following files in the output directory: +For --make gmake, it creates: + {prefix}.mk // Make include file for compiling {prefix}_classes.mk // Make include file with class names +For --make cmake, it creates: + + {prefix}.cmake // CMake include script for compiling + For -cc and -sc mode, it also creates: {prefix}.cpp // Top level C++ file @@ -2406,6 +2420,152 @@ The target system may also require edits to the Makefiles, the simple Makefiles produced by Verilator presume the target system is the same type as the build system. +=head2 CMake + +Verilator can be run using CMake, which takes care of both running +Verilator and compiling the output. There is a CMake example in the +examples/ directory. The following is a minimal CMakeLists.txt that +would build the code listed in "EXAMPLE C++ EXECUTION": + + project(cmake_example) + find_package(verilator HINTS $ENV{VERILATOR_ROOT}) + add_executable(Vour sim_main.cpp) + verilate(Vour SOURCES our.v) + +find_package will automatically find an installed copy of Verilator, or use +a local build if VERILATOR_ROOT is set. + +It is recommended to use CMake >= 3.12 and the Ninja generator, though +other combinations should work. To build with CMake, change to the folder +containing CMakeLists.txt and run: + + mkdir build + cd build + cmake -GNinja .. + ninja + +Or to build with your system default generator: + + mkdir build + cd build + cmake .. + cmake --build . + +If you're building the example you should have an executable to run: + + ./Vour + +The package sets the CMake variables verilator_FOUND, VERILATOR_ROOT and +VERILATOR_BIN to the appropriate values, and also creates a verilate() +function. verilate() will automatically create custom commands to run +Verilator and add the generated C++ sources to the target specified. + + verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name] + [TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE] + [INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...] + [DIRECTORY dir] [VERILATOR_ARGS ...]) + +Lowercase and ... should be replaced with arguments, the uppercase parts +delimit the arguments and can be passed in any order, or left out entirely +if optional. + +verilate(target ...) can be called multiple times to add other verilog +modules to an executable or library target. + +When generating Verilated SystemC sources, you should also include the +SystemC include directories and link to the SystemC libraries. + +Verilator's CMake support provides a convenience function to automatically +find and link to the SystemC library. It can be used as: + + verilator_link_systemc(target) + +where target is the name of your target. + +The search paths can be configured by setting some variables: + +- The variables SYSTEMC_INCLUDE and SYSTEMC_LIBDIR to give a direct path to +the SystemC include an library path. + +- SYSTEMC_ROOT to set the installation prefix of an installed SystemC + library. + +- SYSTEMC to set the installation prefix of an installed SystemC library + (same as above). + +- When using Accellera's SystemC with CMake support, a CMake target is +available that will easen above steps. This will only work if the SystemC +installation can be found by CMake. This can be configured by setting the +CMAKE_PREFIX_PATH variable during CMake configuration. + +Don't forget to set the same C++ standard for the Verilated sources as the +SystemC library. This can be specified using the SYSTEMC_CXX_FLAGS environment +variable. + +=over 4 + +=item target + +Name of a target created by add_executable or add_library. + +=item SOURCES + +List of verilog files to Verilate. Must have at least one file. + +=item PREFIX + +Optional. Sets the Verilator output prefix. Defaults to the name of the +first hdl source with a "V" prepended. Must be unique in each call to +verilate(), so this is necessary if you build a module multiple times with +different parameters. Must be a valid C++ identifer, i.e. contains no +whitespace and only characters A-Z, a-z, 0-9 or _. + +=item TOP_MODULE + +Optional. Sets the name of the top module. Defaults to the name of the +first file in the SOURCES array. + +=item TRACE + +Optional. Enables VCD tracing if present, equivalent to "VERILATOR_ARGS --trace". + +=item TRACE_FST + +Optional. Enables FST tracing if present, equivalent to "VERILATOR_ARGS --trace-fst". + +=item SYSTEMC + +Optional. Enables SystemC mode, defaults to C++ if not specified. + +=item COVERAGE + +Optional. Enables coverage if present, equivalent to "VERILATOR_ARGS --coverage" + +=item INCLUDE_DIRS + +Optional. Sets directories that Verilator searches (same as -y). + +=item OPT_SLOW + +Optional. Set compiler flags for the slow path. You may want to reduce the +optimisation level to improve compile times with large designs. + +=item OPT_FAST + +Optional. Set compiler flags for the fast path. + +=item DIRECTORY + +Optional. Set the verilator output directory. It is preferable to use the +default, which will avoid collisions with other files. + +=item VERILATOR_ARGS + +Optional. Extra arguments to Verilator. Do not specify --Mdir or --prefix +here, use DIRECTORY or PREFIX. + +=back + =head2 Cadence NC-SystemC Models Similar to compiling Verilated designs with gcc, Verilated designs may be diff --git a/configure.ac b/configure.ac index 9c81b9ee7..c380a2961 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ AC_INIT([Verilator],[4.020 devel], # and commit using "devel release" or "Version bump" message AC_CONFIG_HEADER(src/config_build.h) -AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc) +AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake) AC_MSG_RESULT([configuring for $PACKAGE_STRING]) @@ -276,24 +276,37 @@ AC_SUBST(CFG_CXXFLAGS_PARSER) # For some reason -faligned-new does not work under Travis w/ clang but the # configure test doesn't catch this either AS_IF([test "x$TRAVIS_COMPILER" != xclang], [_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-faligned-new)]) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-fbracket-depth=4096) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Qunused-arguments) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-bool-operation) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-parentheses-equality) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-sign-compare) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-uninitialized) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-but-set-variable) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-parameter) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-variable) -_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-shadow) +CFG_CXX_FLAGS_CMAKE="-faligned-new" +m4_foreach([cflag],[ + [-fbracket-depth=4096], + [-Qunused-arguments], + [-Wno-bool-operation], + [-Wno-parentheses-equality], + [-Wno-sign-compare], + [-Wno-uninitialized], + [-Wno-unused-but-set-variable], + [-Wno-unused-parameter], + [-Wno-unused-variable], + [-Wno-shadow]],[ + _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,cflag) + # CMake will test what flags work itself, so pass all flags through to it + CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE cflag" + ]) AC_SUBST(CFG_CXXFLAGS_NO_UNUSED) +AC_SUBST(CFG_CXX_FLAGS_CMAKE) # Find multithread linker flags -_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_THREADS,-mt) -_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_THREADS,-pthread) -_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_THREADS,-lpthread) -_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_THREADS,-latomic) +m4_foreach([ldflag], [ + [-mt], + [-pthread], + [-lpthread], + [-latomic]],[ + _MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_THREADS,ldflag) + # CMake will test what flags work itself, so pass all flags through to it + CFG_LDFLAGS_THREADS_CMAKE="$CFG_LDFLAGS_THREADS_CMAKE ldflag" + ]) AC_SUBST(CFG_LDLIBS_THREADS) +AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE) # Set CFG_WITH_THREADED if can support threading AC_MSG_CHECKING(whether $CXX supports Verilated threads) diff --git a/examples/cmake_hello_c/.gitignore b/examples/cmake_hello_c/.gitignore new file mode 100644 index 000000000..1b2211df0 --- /dev/null +++ b/examples/cmake_hello_c/.gitignore @@ -0,0 +1 @@ +build* diff --git a/examples/cmake_hello_c/CMakeLists.txt b/examples/cmake_hello_c/CMakeLists.txt new file mode 100644 index 000000000..a3b45036c --- /dev/null +++ b/examples/cmake_hello_c/CMakeLists.txt @@ -0,0 +1,37 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake Example: Small CMakeLists.txt +# +# This is an example cmake script to build a verilog to systemc project +# using cmake and verilator. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +# This example builds the tracing_c example using CMake +# To use it, run the following: + +# cd /path/to/verilator/examples/cmake_c +# rm -rf build && mkdir build && cd build +# cmake .. +# cmake --build . + +cmake_minimum_required(VERSION 3.8) +project(cmake_hello_c) + +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if (NOT verilator_FOUND) + message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") +endif() + +# Create a new executable target that will contain all your sources +add_executable(example ../make_hello_c/sim_main.cpp) + +# Add the Verilated circuit to the target +verilate(example + INCLUDE_DIRS "../make_hello_c" + SOURCES ../make_hello_c/top.v) diff --git a/examples/cmake_hello_c/Makefile b/examples/cmake_hello_c/Makefile new file mode 100644 index 000000000..8c0b5ed24 --- /dev/null +++ b/examples/cmake_hello_c/Makefile @@ -0,0 +1,79 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake example usage +# +# This file shows usage of the CMake script. +# This makefile is here for testing the examples and should +# generally not be added to a CMake project. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package install, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). + +ifeq ($(VERILATOR_ROOT),) +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif +###################################################################### + +# Check if CMake is installed and of correct version +ifeq ($(shell which cmake),) +TARGET := nocmake +else +CMAKE_VERSION := $(shell cmake --version | grep -Po '(\d[\.\d]+)') +CMAKE_MAJOR := $(shell echo $(CMAKE_VERSION) | cut -f1 -d.) +CMAKE_MINOR := $(shell echo $(CMAKE_VERSION) | cut -f2 -d.) +CMAKE_GT_3_8 := $(shell [ $(CMAKE_MAJOR) -gt 3 -o \( $(CMAKE_MAJOR) -eq 3 -a $(CMAKE_MINOR) -ge 8 \) ] && echo true) +ifeq ($(CMAKE_GT_3_8),true) +TARGET := run +else +TARGET := oldcmake +endif +endif + +default: $(TARGET) + +run: + @echo + @echo "-- Verilator CMake hello world example" + + @echo + @echo "-- CMake ----------------" + mkdir -p build && cd build && cmake .. + + @echo + @echo "-- COMPILE -----------------" + cmake --build build + + @echo + @echo "-- RUN ---------------------" + build/example + + @echo + @echo "-- DONE --------------------" + @echo + +clean mostlyclean distclean maintainer-clean: + @rm -rf build logs + +nocmake: + @echo + @echo "%Skip: CMake has not been found" + @echo + +oldcmake: + @echo + @echo "%Skip: CMake version is too old (need at least 3.8)" + @echo diff --git a/examples/cmake_hello_sc/.gitignore b/examples/cmake_hello_sc/.gitignore new file mode 100644 index 000000000..1b2211df0 --- /dev/null +++ b/examples/cmake_hello_sc/.gitignore @@ -0,0 +1 @@ +build* diff --git a/examples/cmake_hello_sc/CMakeLists.txt b/examples/cmake_hello_sc/CMakeLists.txt new file mode 100644 index 000000000..3aa7d6714 --- /dev/null +++ b/examples/cmake_hello_sc/CMakeLists.txt @@ -0,0 +1,46 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake Example: Small CMakeLists.txt with SystemC +# +# This is an example cmake script to build a verilog to SystemC project +# using CMake and Verilator. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +# This example builds the tracing_sc example using CMake +# To use it, run the following: + +# cd /path/to/verilator/examples/cmake_sc +# rm -rf build && mkdir build && cd build +# cmake .. +# cmake --build . + +cmake_minimum_required(VERSION 3.8) +project(cmake_hello_sc) + +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if (NOT verilator_FOUND) + message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") +endif() + +# SystemC dependencies +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +# Find SystemC using SystemC's CMake integration +find_package(SystemCLanguage QUIET) + +# Create a new executable target that will contain all your sources +add_executable(example ../make_hello_sc/sc_main.cpp) + +# Add the Verilated circuit to the target +verilate(example SYSTEMC + INCLUDE_DIRS "../make_hello_sc" + SOURCES ../make_hello_sc/top.v) + +verilator_link_systemc(example) diff --git a/examples/cmake_hello_sc/Makefile b/examples/cmake_hello_sc/Makefile new file mode 100644 index 000000000..3e5cb375b --- /dev/null +++ b/examples/cmake_hello_sc/Makefile @@ -0,0 +1,129 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake example usage +# +# This file shows usage of the CMake script. +# This makefile is here for testing the examples and should +# generally not be added to a CMake project. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package install, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). + +ifeq ($(VERILATOR_ROOT),) +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif +###################################################################### + +# Check if CMake is installed and of correct version +ifeq ($(shell which cmake),) + TARGET := nocmake +else +CMAKE_VERSION := $(shell cmake --version | grep -Po '(\d[\.\d]+)') +CMAKE_MAJOR := $(shell echo $(CMAKE_VERSION) | cut -f1 -d.) +CMAKE_MINOR := $(shell echo $(CMAKE_VERSION) | cut -f2 -d.) +CMAKE_GT_3_8 := $(shell [ $(CMAKE_MAJOR) -gt 3 -o \( $(CMAKE_MAJOR) -eq 3 -a $(CMAKE_MINOR) -ge 8 \) ] && echo true) +ifneq ($(CMAKE_GT_3_8),true) +TARGET := oldcmake +else + +# Test existence of SYSTEMC_INCLUDE and SYSTEMC_LIBDIR environment variabless +ifneq (,$(SYSTEMC_INCLUDE)) +ifneq (,${SYSTEMC_LIBDIR}) +SYSTEMC_SET := true +endif +endif + +# Test existence of SYSTEMC_ROOT environment variable +ifneq (SYSTEMC_SET, true) +ifneq (,${SYSTEMC_ROOT}) +SYSTEMC_SET := true +endif +endif + +# Test existence of SYSTEMC environment variable +ifneq (SYSTEMC_SET, true) +ifneq (,${SYSTEMC}) +SYSTEMC_SET := true +endif +endif + +# Test whether SystemC is installed with CMake support +# This will print a CMake error about processing arguments that can (currently) be ignored. +ifneq (SYSTEMC_SET, true) +FINDSC := $(shell mkdir -p build && cd build && cmake --find-package -DNAME=SystemCLanguage -DCMAKE_USE_PTHREADS_INIT=ON -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST -DThreads_FOUND=ON) +ifneq (,$(findstring SystemCLanguage found,$(FINDSC))) +SYSTEMC_SET := true +endif +endif + +ifeq ($(SYSTEMC_SET), true) +TARGET := run +else +TARGET := nosc +endif + +endif +endif + +default: $(TARGET) + +run: + @echo + @echo "-- Verilator CMake SystemC hello-world simple example" + + @echo + @echo "-- CMake ----------------" + mkdir -p build && cd build && cmake .. + + @echo + @echo "-- COMPILE -----------------" + cmake --build build + + @echo + @echo "-- RUN ---------------------" + @mkdir -p logs + build/example + + @echo "-- DONE --------------------" + @echo "Note: Once this example is understood, see examples/cmake_tracing_sc." + @echo "Note: Also see the EXAMPLE section in the verilator manpage/document." + +clean mostlyclean distclean maintainer-clean: + @rm -rf build logs + +nocmake: + @echo + @echo "%Skip: CMake has not been found" + @echo + +oldcmake: + @echo + @echo "%Skip: CMake version is too old (need at least 3.8)" + @echo + +nosc: + @echo + @echo "%Skip: CMake could not find SystemC." + @echo "% Make sure that either:" + @echo "% - The environment variables SYSTEMC_INCLUDE and SYSTEMC_LIBDIR are exported." + @echo "% - Or, the environment variable SYSTEMC_ROOT is exported." + @echo "% - Or, The environment variable SYSTEMC is exported." + @echo "% - Or, if the SystemC installation provides CMake support," + @echo "% that its installation prefix is in CMAKE_PREFIX_PATH." + @echo "% Also that the C++ standard of the SystemC library is the same as this example." + @echo "% Please see the Verilator documentation's CMake section for more information." + @echo diff --git a/examples/cmake_protect_lib/.gitignore b/examples/cmake_protect_lib/.gitignore new file mode 100644 index 000000000..1b2211df0 --- /dev/null +++ b/examples/cmake_protect_lib/.gitignore @@ -0,0 +1 @@ +build* diff --git a/examples/cmake_protect_lib/CMakeLists.txt b/examples/cmake_protect_lib/CMakeLists.txt new file mode 100644 index 000000000..7031eb1c7 --- /dev/null +++ b/examples/cmake_protect_lib/CMakeLists.txt @@ -0,0 +1,60 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake Example: Small CMakeLists.txt +# +# This is an example cmake script to build a verilog to systemc project +# using cmake and verilator. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +# This example builds the tracing_c example using CMake +# To use it, run the following: + +# cd /path/to/verilator/examples/cmake_c +# rm -rf build && mkdir build && cd build +# cmake .. +# cmake --build . + +cmake_minimum_required(VERSION 3.8) +project(cmake_protect_lib) + +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if (NOT verilator_FOUND) + message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") +endif() + +# Create the main executable target +add_executable(example ../make_protect_lib/sim_main.cpp) + +# Create a secret library +add_library(verilated_secret STATIC) # or SHARED for a shared library +target_link_libraries(example PRIVATE verilated_secret) +# To create both libraries on CMake >= 3.12 replace the above 2 lines with the following: +# add_library(verilated_secret OBJECT) +# set_property(TARGET verilated_secret PROPERTY POSITION_INDEPENDENT_CODE 1) +# add_library(verilated_secret_static STATIC $<TARGET_OBJECTS:verilated_secret>) +# set_target_properties(verilated_secret_static PROPERTIES OUTPUT_NAME verilated_secret) +# add_library(verilated_secret_shared SHARED $<TARGET_OBJECTS:verilated_secret>) +# set_target_properties(verilated_secret_shared PROPERTIES OUTPUT_NAME verilated_secret) +# target_link_libraries(example PRIVATE verilated_secret_static) + +# Setup random seed +verilator_generate_key(KEY_INIT) +set(PROTECT_KEY ${KEY_INIT} CACHE STRING "Random seed for protection") + +# Add the Verilated modules to the targets +verilate(verilated_secret + VERILATOR_ARGS --protect-lib verilated_secret + --protect-key ${PROTECT_KEY} + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/verilated_secret + SOURCES ../make_protect_lib/secret_impl.v) + +# Include location of verilated_secret.sv wrapper +verilate(example + VERILATOR_ARGS "-I${CMAKE_CURRENT_BINARY_DIR}/verilated_secret" + SOURCES ../make_protect_lib/top.v) diff --git a/examples/cmake_protect_lib/Makefile b/examples/cmake_protect_lib/Makefile new file mode 100644 index 000000000..a3d3575a6 --- /dev/null +++ b/examples/cmake_protect_lib/Makefile @@ -0,0 +1,79 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake example usage +# +# This file shows usage of the CMake script. +# This makefile is here for testing the examples and should +# generally not be added to a CMake project. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package install, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). + +ifeq ($(VERILATOR_ROOT),) +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif +###################################################################### + +# Check if CMake is installed and of correct version +ifeq ($(shell which cmake),) +TARGET := nocmake +else +CMAKE_VERSION := $(shell cmake --version | grep -Po '(\d[\.\d]+)') +CMAKE_MAJOR := $(shell echo $(CMAKE_VERSION) | cut -f1 -d.) +CMAKE_MINOR := $(shell echo $(CMAKE_VERSION) | cut -f2 -d.) +CMAKE_GT_3_8 := $(shell [ $(CMAKE_MAJOR) -gt 3 -o \( $(CMAKE_MAJOR) -eq 3 -a $(CMAKE_MINOR) -ge 8 \) ] && echo true) +ifeq ($(CMAKE_GT_3_8),true) +TARGET := run +else +TARGET := oldcmake +endif +endif + +default: $(TARGET) + +run: + @echo + @echo "-- Verilator CMake protect_lib example" + + @echo + @echo "-- CMake ----------------" + mkdir -p build && cd build && cmake .. + + @echo + @echo "-- COMPILE -----------------" + cmake --build build + + @echo + @echo "-- RUN ---------------------" + build/example + + @echo + @echo "-- DONE --------------------" + @echo + +clean mostlyclean distclean maintainer-clean: + @rm -rf build logs + +nocmake: + @echo + @echo "%Skip: CMake has not been found" + @echo + +oldcmake: + @echo + @echo "%Skip: CMake version is too old (need at least 3.8)" + @echo diff --git a/examples/cmake_tracing_c/.gitignore b/examples/cmake_tracing_c/.gitignore new file mode 100644 index 000000000..c0b051137 --- /dev/null +++ b/examples/cmake_tracing_c/.gitignore @@ -0,0 +1,2 @@ +build* +logs diff --git a/examples/cmake_tracing_c/CMakeLists.txt b/examples/cmake_tracing_c/CMakeLists.txt new file mode 100644 index 000000000..d0275e9f6 --- /dev/null +++ b/examples/cmake_tracing_c/CMakeLists.txt @@ -0,0 +1,38 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake Example: Small CMakeLists.txt with tracing +# +# This is an example cmake script to build a verilog to systemc project +# using cmake and verilator. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +# This example builds the make_tracing_c example using CMake +# To use it, run the following: + +# cd /path/to/verilator/examples/cmake_tracing_c +# rm -rf build && mkdir build && cd build +# cmake .. +# cmake --build . + +cmake_minimum_required(VERSION 3.8) +project(cmake_tracing_c) + +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if (NOT verilator_FOUND) + message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") +endif() + +# Create a new executable target that will contain all your sources +add_executable(example ../make_tracing_c/sim_main.cpp) + +# Add the Verilated circuit to the target +verilate(example COVERAGE TRACE + INCLUDE_DIRS "../make_tracing_c" + VERILATOR_ARGS -f ../make_tracing_c/input.vc -O2 -x-assign 0 + SOURCES ../make_tracing_c/top.v) diff --git a/examples/cmake_tracing_c/Makefile b/examples/cmake_tracing_c/Makefile new file mode 100644 index 000000000..a6490a328 --- /dev/null +++ b/examples/cmake_tracing_c/Makefile @@ -0,0 +1,85 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake example usage +# +# This file shows usage of the CMake script. +# This makefile is here for testing the examples and should +# generally not be added to a CMake project. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package install, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). + +ifeq ($(VERILATOR_ROOT),) +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif +###################################################################### + +# Check if CMake is installed and of correct version +ifeq ($(shell which cmake),) +TARGET := nocmake +else +CMAKE_VERSION := $(shell cmake --version | grep -Po '(\d[\.\d]+)') +CMAKE_MAJOR := $(shell echo $(CMAKE_VERSION) | cut -f1 -d.) +CMAKE_MINOR := $(shell echo $(CMAKE_VERSION) | cut -f2 -d.) +CMAKE_GT_3_8 := $(shell [ $(CMAKE_MAJOR) -gt 3 -o \( $(CMAKE_MAJOR) -eq 3 -a $(CMAKE_MINOR) -ge 8 \) ] && echo true) +ifeq ($(CMAKE_GT_3_8),true) +TARGET := run +else +TARGET := oldcmake +endif +endif + +default: $(TARGET) + +run: + @echo + @echo "-- Verilator CMake tracing example" + + @echo + @echo "-- CMake ----------------" + mkdir -p build && cd build && cmake .. + + @echo + @echo "-- COMPILE -----------------" + cmake --build build + + @echo + @echo "-- RUN ---------------------" + @mkdir -p logs + build/example +trace + + @echo + @echo "-- COVERAGE ----------------" + $(VERILATOR_COVERAGE) --annotate logs/annotated logs/coverage.dat + + @echo + @echo "-- DONE --------------------" + @echo "To see waveforms, open vlt_dump.vcd in a waveform viewer" + @echo + +clean mostlyclean distclean maintainer-clean: + @rm -rf build logs + +nocmake: + @echo + @echo "%Skip: CMake has not been found" + @echo + +oldcmake: + @echo + @echo "%Skip: CMake version is too old (need at least 3.8)" + @echo diff --git a/examples/cmake_tracing_sc/.gitignore b/examples/cmake_tracing_sc/.gitignore new file mode 100644 index 000000000..284951c31 --- /dev/null +++ b/examples/cmake_tracing_sc/.gitignore @@ -0,0 +1,7 @@ +*.dmp +*.log +*.csrc +*.vcd +obj_* +logs +build* diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt new file mode 100644 index 000000000..927d11b8f --- /dev/null +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -0,0 +1,47 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake Example: Small CMakeLists.txt with SystemC tracing +# +# This is an example cmake script to build a verilog to SystemC project +# using CMake and Verilator. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +# This example builds the tracing_sc example using CMake +# To use it, run the following: + +# cd /path/to/verilator/examples/cmake_tracing_sc +# rm -rf build && mkdir build && cd build +# cmake .. +# cmake --build . + +cmake_minimum_required(VERSION 3.8) +project(cmake_tracing_sc_example) + +find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) +if (NOT verilator_FOUND) + message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") +endif() + +# SystemC dependencies +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +# Find SystemC using SystemC's CMake integration +find_package(SystemCLanguage QUIET) + +# Create a new executable target that will contain all your sources +add_executable(example ../make_tracing_sc/sc_main.cpp) + +# Add the Verilated circuit to the target +verilate(example SYSTEMC COVERAGE TRACE + INCLUDE_DIRS "../make_tracing_sc" + VERILATOR_ARGS -f ../make_tracing_sc/input.vc -O2 -x-assign 0 + SOURCES ../make_tracing_sc/top.v) + +verilator_link_systemc(example) diff --git a/examples/cmake_tracing_sc/Makefile b/examples/cmake_tracing_sc/Makefile new file mode 100644 index 000000000..392cf53b4 --- /dev/null +++ b/examples/cmake_tracing_sc/Makefile @@ -0,0 +1,134 @@ +###################################################################### +# +# DESCRIPTION: Verilator CMake example usage +# +# This file shows usage of the CMake script. +# This makefile is here for testing the examples and should +# generally not be added to a CMake project. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +###################################################################### +# Set up variables + +# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a +# package install, and verilator is in your path. Otherwise find the +# binary relative to $VERILATOR_ROOT (such as when inside the git sources). + +ifeq ($(VERILATOR_ROOT),) +VERILATOR_COVERAGE = verilator_coverage +else +export VERILATOR_ROOT +VERILATOR_COVERAGE = $(VERILATOR_ROOT)/bin/verilator_coverage +endif +###################################################################### + +# Check if CMake is installed and of correct version +ifeq ($(shell which cmake),) + TARGET := nocmake +else +CMAKE_VERSION := $(shell cmake --version | grep -Po '(\d[\.\d]+)') +CMAKE_MAJOR := $(shell echo $(CMAKE_VERSION) | cut -f1 -d.) +CMAKE_MINOR := $(shell echo $(CMAKE_VERSION) | cut -f2 -d.) +CMAKE_GT_3_8 := $(shell [ $(CMAKE_MAJOR) -gt 3 -o \( $(CMAKE_MAJOR) -eq 3 -a $(CMAKE_MINOR) -ge 8 \) ] && echo true) +ifneq ($(CMAKE_GT_3_8),true) +TARGET := oldcmake +else + +# Test existence of SYSTEMC_INCLUDE and SYSTEMC_LIBDIR environment variabless +ifneq (,$(SYSTEMC_INCLUDE)) +ifneq (,${SYSTEMC_LIBDIR}) +SYSTEMC_SET := true +endif +endif + +# Test existence of SYSTEMC_ROOT environment variable +ifneq (SYSTEMC_SET, true) +ifneq (,${SYSTEMC_ROOT}) +SYSTEMC_SET := true +endif +endif + +# Test existence of SYSTEMC environment variable +ifneq (SYSTEMC_SET, true) +ifneq (,${SYSTEMC}) +SYSTEMC_SET := true +endif +endif + +# Test whether SystemC is installed with CMake support +# This will print a CMake error about processing arguments that can (currently) be ignored. +ifneq (SYSTEMC_SET, true) +FINDSC := $(shell mkdir -p build && cd build && cmake --find-package -DNAME=SystemCLanguage -DCMAKE_USE_PTHREADS_INIT=ON -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST -DThreads_FOUND=ON) +ifneq (,$(findstring SystemCLanguage found,$(FINDSC))) +SYSTEMC_SET := true +endif +endif + +ifeq ($(SYSTEMC_SET), true) +TARGET := run +else +TARGET := nosc +endif + +endif +endif + +default: $(TARGET) + +run: + @echo + @echo "-- Verilator CMake SystemC tracing example" + + @echo + @echo "-- CMake ----------------" + mkdir -p build && cd build && cmake .. + + @echo + @echo "-- COMPILE -----------------" + cmake --build build + + @echo + @echo "-- RUN ---------------------" + @mkdir -p logs + build/example +trace + + @echo + @echo "-- COVERAGE ----------------" + $(VERILATOR_COVERAGE) --annotate logs/annotated logs/coverage.dat + + @echo + @echo "-- DONE --------------------" + @echo "To see waveforms, open vlt_dump.vcd in a waveform viewer" + @echo + +clean mostlyclean distclean maintainer-clean: + @rm -rf build logs + +nocmake: + @echo + @echo "%Skip: CMake has not been found" + @echo + +oldcmake: + @echo + @echo "%Skip: CMake version is too old (need at least 3.8)" + @echo + +nosc: + @echo + @echo "%Skip: CMake could not find SystemC." + @echo "% Make sure that either:" + @echo "% - The environment variables SYSTEMC_INCLUDE and SYSTEMC_LIBDIR are exported." + @echo "% - Or, the environment variable SYSTEMC_ROOT is exported." + @echo "% - Or, The environment variable SYSTEMC is exported." + @echo "% - Or, if the SystemC installation provides CMake support," + @echo "% that its installation prefix is in CMAKE_PREFIX_PATH." + @echo "% Also that the C++ standard of the SystemC library is the same as this example." + @echo "% Please see the Verilator documentation's CMake section for more information." + @echo diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 74a3b0173..859af6403 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -183,6 +183,7 @@ RAW_OBJS = \ V3EmitC.o \ V3EmitCInlines.o \ V3EmitCSyms.o \ + V3EmitCMake.o \ V3EmitMk.o \ V3EmitV.o \ V3EmitXml.o \ diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp new file mode 100644 index 000000000..bd254bd4f --- /dev/null +++ b/src/V3EmitCMake.cpp @@ -0,0 +1,206 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit CMake file list +// +// Code available from: http://www.veripool.org/verilator +// +//************************************************************************* +// +// Copyright 2004-2019 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3Os.h" +#include "V3EmitCMake.h" +#include "V3EmitCBase.h" + +#include <memory> + +//###################################################################### +// Emit statements + +class CMakeEmitter { + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + // STATIC FUNCTIONS + + // Concatenate all strings in 'strs' with ' ' between them. + template<typename List> + static string cmake_list(const List& strs) { + string s; + if (strs.begin() != strs.end()) { + s.append("\""); + s.append(*strs.begin()); + s.append("\""); + for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) { + s.append(" \""); + s.append(*it); + s.append("\""); + } + } + return s; + } + + // Print CMake variable set command: output raw_value unmodified + // cache_type should be empty for a normal variable + // "BOOL", "FILEPATH", "PATH", "STRING" or "INTERNAL" for a CACHE variable + // See https://cmake.org/cmake/help/latest/command/set.html + static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value, + const string& cache_type = "", const string& docstring = "") { + of << "set(" << name << " " << raw_value; + if (!cache_type.empty()) { + of << " CACHE " << cache_type << " \"" << docstring << "\""; + } + of << ")\n"; + } + + static void cmake_set(std::ofstream& of, const string& name, const string& value, + const string& cache_type = "", const string& docstring = "") { + string raw_value = "\"" + value + "\""; + cmake_set_raw(of, name, raw_value, cache_type, docstring); + } + + //Swap all backslashes for forward slashes, because of Windows + static string deslash(const string& s) { + std::string res = s; + for (string::iterator it = res.begin(); it != res.end(); ++it) { + if (*it == '\\') + *it = '/'; + } + return res; + } + + static void emitOverallCMake() { + const vl_unique_ptr<std::ofstream> + of (V3File::new_ofstream(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".cmake")); + string name = v3Global.opt.prefix(); + + *of << "# Verilated -*- CMake -*-\n"; + *of << "# DESCR" "IPTION: Verilator output: CMake include script with class lists\n"; + *of << "#\n"; + *of << "# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n"; + *of << "# This file is meant to be consumed by the verilate() function,\n"; + *of << "# which becomes available after executing `find_package(verilator).\n"; + + *of << "\n### Constants...\n"; + cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), + "FILEPATH", "Perl executable (from $PERL)"); + cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), + "PATH", "Path to Verilator kit (from $VERILATOR_ROOT)"); + + *of << "\n### Compiler flags...\n"; + + *of << "# User CFLAGS (from -CFLAGS on Verilator command line)\n"; + cmake_set_raw(*of, name + "_USER_CFLAGS", cmake_list(v3Global.opt.cFlags())); + + *of << "# User LDLIBS (from -LDFLAGS on Verilator command line)\n"; + cmake_set_raw(*of, name + "_USER_LDLIBS", cmake_list(v3Global.opt.ldLibs())); + + *of << "\n### Switches...\n"; + + *of << "# SystemC output mode? 0/1 (from --sc)\n"; + cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0"); + *of << "# Coverage output mode? 0/1 (from --coverage)\n"; + cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage()?"1":"0"); + *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; + cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); + *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; + cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))?"1":"0"); + *of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n"; + cmake_set_raw(*of, name + "_TRACE_FST", (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) ? "1":"0"); + + *of << "\n### Sources...\n"; + std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global; + for (AstFile* nodep = v3Global.rootp()->filesp(); nodep; + nodep = VN_CAST(nodep->nextp(), File)) { + AstCFile* cfilep = VN_CAST(nodep, CFile); + if (cfilep && cfilep->source()) { + if (cfilep->support()) { + if (cfilep->slow()) { + support_slow.push_back(cfilep->name()); + } else { + support_fast.push_back(cfilep->name()); + } + } else { + if (cfilep->slow()) { + classes_slow.push_back(cfilep->name()); + } else { + classes_fast.push_back(cfilep->name()); + } + } + } + } + + global.push_back("${VERILATOR_ROOT}/include/verilated.cpp"); + if (v3Global.dpi()) { + global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp"); + } + if (v3Global.opt.vpi()) { + global.push_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp"); + } + if (v3Global.opt.savable()) { + global.push_back("${VERILATOR_ROOT}/include/verilated_save.cpp"); + } + if (v3Global.opt.coverage()) { + global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp"); + } + if (v3Global.opt.trace()) { + global.push_back("${VERILATOR_ROOT}/include/" + + v3Global.opt.traceSourceName()+"_c.cpp"); + if (v3Global.opt.systemC()) { + if (v3Global.opt.traceFormat() != TraceFormat::VCD) { + v3error("Unsupported: This trace format is not supported in SystemC, use VCD format."); + } + global.push_back("${VERILATOR_ROOT}/include/" + + v3Global.opt.traceSourceName()+"_sc.cpp"); + } + } + if (v3Global.opt.mtasks()) { + global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); + } + if (!v3Global.opt.protectLib().empty()) { + global.push_back(v3Global.opt.makeDir()+"/"+v3Global.opt.protectLib()+".cpp"); + } + + *of << "# Global classes, need linked once per executable\n"; + cmake_set_raw(*of, name + "_GLOBAL", deslash(cmake_list(global))); + *of << "# Generated module classes, non-fast-path, compile with low/medium optimization\n"; + cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow))); + *of << "# Generated module classes, fast-path, compile with highest optimization\n"; + cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast))); + *of << "# Generated support classes, non-fast-path, compile with low/medium optimization\n"; + cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow))); + *of << "# Generated support classes, fast-path, compile with highest optimization\n"; + cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast))); + + *of << "# All dependencies\n"; + cmake_set_raw(*of, name + "_DEPS", deslash(cmake_list(V3File::getAllDeps()))); + + *of << "# User .cpp files (from .cpp's on Verilator command line)\n"; + cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles()))); + } +public: + explicit CMakeEmitter() { + emitOverallCMake(); + } + virtual ~CMakeEmitter() {} +}; + +void V3EmitCMake::emit() { + UINFO(2,__FUNCTION__<<": "<<endl); + CMakeEmitter emitter; +} diff --git a/src/V3EmitCMake.h b/src/V3EmitCMake.h new file mode 100644 index 000000000..9f90bb2e6 --- /dev/null +++ b/src/V3EmitCMake.h @@ -0,0 +1,34 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit CMake file list +// +// Code available from: http://www.veripool.org/verilator +// +//************************************************************************* +// +// Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// +// Verilator is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +//************************************************************************* + +#ifndef _V3EMITCMAKE_H_ +#define _V3EMITCMAKE_H_ 1 + +#include "config_build.h" +#include "verilatedos.h" + +//============================================================================ + +class V3EmitCMake { +public: + static void emit(); +}; + +#endif // Guard diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 6fe968e53..7666da49f 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -26,16 +26,10 @@ #include "V3EmitMk.h" #include "V3EmitCBase.h" -#include <algorithm> -#include <cmath> -#include <cstdarg> -#include <map> -#include <vector> - //###################################################################### // Emit statements and math operators -class EmitMkVisitor : public EmitCBaseVisitor { +class EmitMk { public: // METHODS @@ -252,23 +246,18 @@ public: of.putsHeader(); } - //-------------------- - virtual void visit(AstNode* nodep) { // LCOV_EXCL_LINE - nodep->v3fatalSrc("No visitors implemented."); - } - public: - explicit EmitMkVisitor(AstNetlist*) { + explicit EmitMk() { emitClassMake(); emitOverallMake(); } - virtual ~EmitMkVisitor() {} + virtual ~EmitMk() {} }; //###################################################################### // Gate class functions -void V3EmitMk::emitmk(AstNetlist* nodep) { +void V3EmitMk::emitmk() { UINFO(2,__FUNCTION__<<": "<<endl); - EmitMkVisitor visitor (nodep); + EmitMk emitter; } diff --git a/src/V3EmitMk.h b/src/V3EmitMk.h index 29bcb4113..1653af5ec 100644 --- a/src/V3EmitMk.h +++ b/src/V3EmitMk.h @@ -24,14 +24,11 @@ #include "config_build.h" #include "verilatedos.h" -#include "V3Error.h" -#include "V3Ast.h" - //============================================================================ class V3EmitMk { public: - static void emitmk(AstNetlist* nodep); + static void emitmk(); }; #endif // Guard diff --git a/src/V3File.cpp b/src/V3File.cpp index 3c4f1da9f..65c2f617e 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -65,17 +65,19 @@ class V3FileDependImp { class DependFile { // A single file bool m_target; // True if write, else read + bool m_exists; string m_filename; // Filename struct stat m_stat; // Stat information public: DependFile(const string& filename, bool target) - : m_target(target), m_filename(filename) { + : m_target(target), m_exists(true), m_filename(filename) { m_stat.st_ctime = 0; m_stat.st_mtime = 0; } ~DependFile() {} const string& filename() const { return m_filename; } bool target() const { return m_target; } + bool exists() const { return m_exists; } off_t size() const { return m_stat.st_size; } ino_t ino() const { return m_stat.st_ino; } time_t cstime() const { return m_stat.st_ctime; } // Seconds @@ -89,6 +91,7 @@ class V3FileDependImp { if (err!=0) { memset(&m_stat, 0, sizeof(m_stat)); m_stat.st_mtime = 1; + m_exists = false; // Not an error... This can occur due to `line directives in the .vpp files UINFO(1,"-Info: File not statable: "<<filename()<<endl); } @@ -125,6 +128,7 @@ public: } } void writeDepend(const string& filename); + std::vector<string> getAllDeps() const; void writeTimes(const string& filename, const string& cmdlineIn); bool checkTimes(const string& filename, const string& cmdlineIn); }; @@ -168,6 +172,17 @@ inline void V3FileDependImp::writeDepend(const string& filename) { } } +inline std::vector<string> V3FileDependImp::getAllDeps() const { + std::vector<string> r; + for (std::set<DependFile>::const_iterator iter=m_filenameList.begin(); + iter!=m_filenameList.end(); ++iter) { + if (!iter->target() && iter->exists()) { + r.push_back(iter->filename()); + } + } + return r; +} + inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { const vl_unique_ptr<std::ofstream> ofp (V3File::new_ofstream(filename)); if (ofp->fail()) v3fatal("Can't write "<<filename); @@ -283,6 +298,9 @@ void V3File::addTgtDepend(const string& filename) { void V3File::writeDepend(const string& filename) { dependImp.writeDepend(filename); } +std::vector<string> V3File::getAllDeps() { + return dependImp.getAllDeps(); +} void V3File::writeTimes(const string& filename, const string& cmdlineIn) { dependImp.writeTimes(filename, cmdlineIn); } diff --git a/src/V3File.h b/src/V3File.h index 3659ad0a0..05ec77ee8 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -29,6 +29,7 @@ #include <stack> #include <set> #include <list> +#include <vector> #include <fstream> //============================================================================ @@ -65,6 +66,7 @@ public: static void addSrcDepend(const string& filename); static void addTgtDepend(const string& filename); static void writeDepend(const string& filename); + static std::vector<string> getAllDeps(); static void writeTimes(const string& filename, const string& cmdlineIn); static bool checkTimes(const string& filename, const string& cmdlineIn); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1b8431cc4..fc4903091 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -534,6 +534,12 @@ void V3Options::notify() { && !cdc()) { v3fatal("verilator: Need --cc, --sc, --cdc, --lint-only, --xml_only or --E option"); } + + // Make sure at least one make system is enabled + if (!m_gmake && !m_cmake) { + m_gmake = true; + } + if (protectIds()) { FileLine* cmdfl = new FileLine(FileLine::commandLineFilename()); if (allPublic()) { @@ -889,6 +895,16 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if (!strcmp(sw, "-l2name")) { // Historical and undocumented m_l2Name = "v"; } + else if (!strcmp(sw, "-make")) { + shift; + if (!strcmp(argv[i], "cmake")) { + m_cmake = true; + } else if (!strcmp(argv[i], "gmake")) { + m_gmake = true; + } else { + fl->v3fatal("Unknown --make system specified: '"<<argv[i]<<"'"); + } + } else if (!strcmp(sw, "-no-l2name")) { // Historical and undocumented m_l2Name = ""; } @@ -1323,6 +1339,7 @@ V3Options::V3Options() { m_bboxSys = false; m_bboxUnsup = false; m_cdc = false; + m_cmake = false; m_coverageLine = false; m_coverageToggle = false; m_coverageUnderscore = false; @@ -1341,6 +1358,7 @@ V3Options::V3Options() { m_ignc = false; m_inhibitSim = false; m_lintOnly = false; + m_gmake = false; m_makeDepend = true; m_makePhony = false; m_orderClockDly = true; diff --git a/src/V3Options.h b/src/V3Options.h index a88a40edf..de71e864f 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -109,6 +109,7 @@ class V3Options { bool m_bboxSys; // main switch: --bbox-sys bool m_bboxUnsup; // main switch: --bbox-unsup bool m_cdc; // main switch: --cdc + bool m_cmake; // main switch: --make cmake bool m_coverageLine; // main switch: --coverage-block bool m_coverageToggle;// main switch: --coverage-toggle bool m_coverageUnderscore;// main switch: --coverage-underscore @@ -127,6 +128,7 @@ class V3Options { bool m_ignc; // main switch: --ignc bool m_inhibitSim; // main switch: --inhibit-sim bool m_lintOnly; // main switch: --lint-only + bool m_gmake; // main switch: --make gmake bool m_orderClockDly;// main switch: --order-clock-delay bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified bool m_pinsScUint; // main switch: --pins-sc-uint @@ -282,6 +284,7 @@ class V3Options { bool bboxSys() const { return m_bboxSys; } bool bboxUnsup() const { return m_bboxUnsup; } bool cdc() const { return m_cdc; } + bool cmake() const { return m_cmake; } bool coverage() const { return m_coverageLine || m_coverageToggle || m_coverageUser; } bool coverageLine() const { return m_coverageLine; } bool coverageToggle() const { return m_coverageToggle; } @@ -298,6 +301,7 @@ class V3Options { bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpDefines; } bool exe() const { return m_exe; } + bool gmake() const { return m_gmake; } bool threadsDpiPure() const { return m_threadsDpiPure; } bool threadsDpiUnpure() const { return m_threadsDpiUnpure; } bool threadsCoarsen() const { return m_threadsCoarsen; } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 54e5b34b2..99efc6830 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -43,6 +43,7 @@ #include "V3DepthBlock.h" #include "V3Descope.h" #include "V3EmitC.h" +#include "V3EmitCMake.h" #include "V3EmitMk.h" #include "V3EmitV.h" #include "V3EmitXml.h" @@ -565,7 +566,12 @@ void process() { && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // Makefile must be after all other emitters - V3EmitMk::emitmk(v3Global.rootp()); + if (v3Global.opt.cmake()) { + V3EmitCMake::emit(); + } + if (v3Global.opt.gmake()) { + V3EmitMk::emitmk(); + } } // Note early return above when opt.cdc() @@ -596,6 +602,7 @@ int main(int argc, char** argv, char** env) { // Validate settings (aka Boost.Program_options) v3Global.opt.notify(); + V3Error::abortIfErrors(); // Can we skip doing everything if times are ok? diff --git a/test_regress/CMakeLists.txt b/test_regress/CMakeLists.txt new file mode 100644 index 000000000..db053f6dd --- /dev/null +++ b/test_regress/CMakeLists.txt @@ -0,0 +1,105 @@ +###################################################################### +# +# DESCRIPTION: CMake script for regression tests +# +# This CMake file is meant to be consumed by regression tests. +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +cmake_minimum_required(VERSION 3.8) +set(TEST_REQUIRED_VARS NAME CSOURCES OPT_FAST VERILATOR_ROOT VERILATOR_ARGS + VERILATOR_SOURCES SYSTEMC VERBOSE VERILATION) +foreach(var ${TEST_REQUIRED_VARS}) + if (NOT DEFINED TEST_${var}) + message(FATAL_ERROR "TEST_${var} not defined. This CMakeLists.txt file is meant to be run by driver.pl.") + endif() +endforeach() + +project("${TEST_NAME}") + +if(TEST_VERBOSE) + add_definitions(-DTEST_VERBOSE=1) +endif() + +separate_arguments(TEST_VERILATOR_ARGS UNIX_COMMAND "${TEST_VERILATOR_ARGS}") + +# filter out empty arguments +list(FILTER TEST_VERILATOR_ARGS EXCLUDE REGEX "$^") + +set(TEST_PREFIX ${TEST_NAME}) + +# If --ARG <val> is present, set OUT = <val> +function(getarg LST ARG OUT) + list(FIND ${LST} ${ARG} _INDEX) + if(NOT _INDEX EQUAL -1) + list(REMOVE_AT ${LST} ${_INDEX}) + list(GET ${LST} ${_INDEX} VAL) + set(${OUT} ${VAL} PARENT_SCOPE) + endif() +endfunction() + +# Normalise -- to - +string(REGEX REPLACE "(^|;)--" "\\1-" + TEST_VERILATOR_ARGS_NORM + "${TEST_VERILATOR_ARGS}") + +getarg(TEST_VERILATOR_ARGS_NORM "-prefix" TEST_PREFIX) +getarg(TEST_VERILATOR_ARGS_NORM "-threads" TEST_THREADS) + +# Strip unwanted args with 1 parameter +string(REGEX REPLACE "(^|;)--?(Mdir|make|prefix|threads);[^;]*" "" + TEST_VERILATOR_ARGS + "${TEST_VERILATOR_ARGS}") +# Strip unwanted args +string(REGEX REPLACE "(^|;)--?(sc|cc)" "" + TEST_VERILATOR_ARGS + "${TEST_VERILATOR_ARGS}") + +separate_arguments(TEST_VERILATOR_SOURCES UNIX_COMMAND "${TEST_VERILATOR_SOURCES}") +# filter out empty sources +list(FILTER TEST_VERILATOR_SOURCES EXCLUDE REGEX "$^") + +find_package(verilator REQUIRED HINTS ${TEST_VERILATOR_ROOT}) + +set(verilate_ARGS MAIN) +if(TEST_PREFIX) + list(APPEND verilate_ARGS PREFIX ${TEST_PREFIX}) +endif() +if(TEST_OPT_FAST) + list(APPEND verilate_ARGS OPT_FAST ${TEST_OPT_FAST}) +endif() +if(TEST_THREADS) + list(APPEND verilate_ARGS THREADS ${TEST_THREADS}) +endif() +if(TEST_SYSTEMC) + list(APPEND verilate_ARGS SYSTEMC) +endif() + +set(TARGET_NAME "V${TEST_NAME}") + +add_executable(${TARGET_NAME} ${TEST_CSOURCES}) + +if(TEST_VERILATION) + verilate(${TARGET_NAME} ${verilate_ARGS} + VERILATOR_ARGS ${TEST_VERILATOR_ARGS} + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${TEST_VERILATOR_SOURCES}) +endif() + +if(TEST_SYSTEMC) + verilator_link_systemc("${TARGET_NAME}") +endif() + +string(TOUPPER "${TEST_NAME}" TEST_NAME_UC) + +target_compile_definitions(${TARGET_NAME} PRIVATE + "TEST_OBJ_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "VM_PREFIX=${TEST_PREFIX}" + "VM_PREFIX_INCLUDE=<${TEST_PREFIX}.h>" + "${TEST_NAME_UC}" +) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index cb23b4e6f..3b62cf01a 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -19,6 +19,7 @@ use Data::Dumper; $Data::Dumper::Sortkeys=1; use FindBin qw($RealBin); use strict; use vars qw($Debug %Vars $Driver $Fork); +use version; use POSIX qw(strftime); use lib "."; use Time::HiRes qw(usleep); @@ -601,6 +602,7 @@ sub new { verilator_flags2 => [], verilator_flags3 => ["--clk clk"], verilator_make_gmake => 1, + verilator_make_cmake => 0, verilated_debug => $Opt_Verilated_Debug, stdout_filename => undef, # Redirect stdout %$self}; @@ -768,6 +770,21 @@ sub _read_status { #---------------------------------------------------------------------- # Methods invoked by tests +sub compile_vlt_cmd { + my $self = (ref $_[0]? shift : $Self); + my %param = (%{$self}, @_); # Default arguments are from $self + return 1 if $self->errors || $self->skips || $self->unsupporteds; + + my @vlt_cmd = ( + "perl", "$ENV{VERILATOR_ROOT}/bin/verilator", + $self->compile_vlt_flags(%param), + $param{top_filename}, + @{$param{v_other_filenames}}, + $param{stdout_filename}?"> ".$param{stdout_filename}:"" + ); + return @vlt_cmd; +} + sub compile_vlt_flags { my $self = (ref $_[0]? shift : $Self); my %param = (%{$self}, @_); # Default arguments are from $self @@ -798,6 +815,8 @@ sub compile_vlt_flags { unshift @verilator_flags, "--threads $threads" if $param{vltmt} && $checkflags !~ /-threads /; unshift @verilator_flags, "--trace-fst-thread" if $param{vltmt} && $checkflags =~ /-trace-fst/; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; + unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake}; + unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake}; if (defined $opt_optimize) { my $letters = ""; if ($opt_optimize =~ /[a-zA-Z]/) { @@ -812,7 +831,7 @@ sub compile_vlt_flags { unshift @verilator_flags, "--O".$letters; } - my @cmdargs = ("perl", "$ENV{VERILATOR_ROOT}/bin/verilator", + my @cmdargs = ( "--prefix ".$param{VM_PREFIX}, @verilator_flags, @{$param{verilator_flags2}}, @@ -822,9 +841,6 @@ sub compile_vlt_flags { # Flags from driver cmdline override default flags and # flags from the test itself @Opt_Driver_Verilator_Flags, - $param{top_filename}, - @{$param{v_other_filenames}}, - ($param{stdout_filename}?"> ".$param{stdout_filename}:""), ); return @cmdargs; } @@ -849,7 +865,7 @@ sub compile { return 1 if $self->errors || $self->skips || $self->unsupporteds; $self->oprint("Compile\n") if $self->{verbose}; - compile_vlt_flags(%param); + compile_vlt_cmd(%param); if (!$self->{make_top_shell}) { $param{top_shell_filename} @@ -972,7 +988,6 @@ sub compile { ]); } elsif ($param{vlt_all}) { - my @cmdargs = $self->compile_vlt_flags(%param); if ($self->sc && !$self->have_sc) { $self->skip("Test requires SystemC; ignore error since not installed\n"); @@ -984,33 +999,79 @@ sub compile { return 1; } + if ($param{verilator_make_cmake} && !$self->have_cmake) { + $self->skip("Test requires CMake; ignore error since not available or version too old\n"); + return 1; + } + if (!$param{fails} && $param{make_main}) { $self->_make_main(); } - $self->_run(logfile=>"$self->{obj_dir}/vlt_compile.log", - fails=>$param{fails}, - tee=>$param{tee}, - expect=>$param{expect}, - expect_filename=>$param{expect_filename}, - cmd=>\@cmdargs) if $::Opt_Verilation; - return 1 if $self->errors || $self->skips || $self->unsupporteds; + if ($param{verilator_make_gmake} + || (!$param{verilator_make_gmake} && !$param{verilator_make_cmake})) { + my @vlt_cmd = $self->compile_vlt_cmd(%param); + $self->oprint("Running Verilator (gmake)\n") if $self->{verbose}; + $self->_run(logfile => "$self->{obj_dir}/vlt_compile.log", + fails => $param{fails}, + tee => $param{tee}, + expect => $param{expect}, + expect_filename => $param{expect_filename}, + cmd => \@vlt_cmd) if $::Opt_Verilation; + return 1 if $self->errors || $self->skips || $self->unsupporteds; + } + + if ($param{verilator_make_cmake}) { + my @vlt_args = $self->compile_vlt_flags(%param); + $self->oprint("Running cmake\n") if $self->{verbose}; + mkdir $self->{obj_dir}; + my @csources = (); + unshift @csources, $self->{main_filename} if $param{make_main}; + $self->_run(logfile => "$self->{obj_dir}/vlt_cmake.log", + fails => $param{fails}, + tee => $param{tee}, + expect => $param{expect}, + expect_filename => $param{expect_filename}, + cmd => ["cd \"".$self->{obj_dir}."\" && cmake", + "\"".$self->{t_dir}."/..\"", + "-DTEST_VERILATOR_ROOT=$ENV{VERILATOR_ROOT}", + "-DTEST_NAME=$self->{name}", + "-DTEST_CSOURCES=\"@csources\"", + "-DTEST_VERILATOR_ARGS=\"@vlt_args\"", + "-DTEST_VERILATOR_SOURCES=\"$param{top_filename} @{$param{v_other_filenames}}\"", + "-DTEST_VERBOSE=\"".($self->{verbose} ? 1 : 0)."\"", + "-DTEST_SYSTEMC=\"" .($self->sc ? 1 : 0). "\"", + "-DCMAKE_PREFIX_PATH=\"".(($ENV{SYSTEMC_INCLUDE}||$ENV{SYSTEMC}||'')."/..\""), + "-DTEST_OPT_FAST=\"" . ($param{benchmark}?"-O2":"") . "\"", + "-DTEST_VERILATION=\"" . $::Opt_Verilation . "\"", + ]); + return 1 if $self->errors || $self->skips || $self->unsupporteds; + } if (!$param{fails} && $param{verilator_make_gmake}) { - $self->oprint("GCC\n") if $self->{verbose}; - $self->_run(logfile=>"$self->{obj_dir}/vlt_gcc.log", - cmd=>["make", - "-C ".$self->{obj_dir}, - "-f ".$::RealBin."/Makefile_obj", - ($self->{verbose} ? "" : "--no-print-directory"), - "VM_PREFIX=$self->{VM_PREFIX}", - "TEST_OBJ_DIR=$self->{obj_dir}", - "CPPFLAGS_DRIVER=-D".uc($self->{name}), - ($opt_verbose ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1":""), - ($param{make_main}?"":"MAKE_MAIN=0"), - ($param{benchmark}?"OPT_FAST=-O2":""), - "$self->{VM_PREFIX}", # bypass default rule, as we don't need archive - ($param{make_flags}||""), + $self->oprint("Running make (gmake)\n") if $self->{verbose}; + $self->_run(logfile => "$self->{obj_dir}/vlt_gcc.log", + cmd => ["make", + "-C ".$self->{obj_dir}, + "-f ".$::RealBin."/Makefile_obj", + ($self->{verbose} ? "" : "--no-print-directory"), + "VM_PREFIX=$self->{VM_PREFIX}", + "TEST_OBJ_DIR=$self->{obj_dir}", + "CPPFLAGS_DRIVER=-D".uc($self->{name}), + ($opt_verbose ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1":""), + ($param{make_main}?"":"MAKE_MAIN=0"), + ($param{benchmark}?"OPT_FAST=-O2":""), + "$self->{VM_PREFIX}", # bypass default rule, as we don't need archive + ($param{make_flags}||""), + ]); + } + + if (!$param{fails} && $param{verilator_make_cmake}) { + $self->oprint("Running cmake --build\n") if $self->{verbose}; + $self->_run(logfile => "$self->{obj_dir}/vlt_cmake_build.log", + cmd => ["cmake", + "--build", $self->{obj_dir}, + ($self->{verbose}?"--verbose":""), ]); } } @@ -1273,6 +1334,23 @@ sub have_sc { return 0; } +sub have_cmake { + return cmake_version() >= version->declare("3.8"); +} + +sub cmake_version { + chomp(my $cmake_bin = `which cmake`); + if (!$cmake_bin) { + return undef; + } + my $cmake_version = `cmake --version`; + if ($cmake_version !~ /cmake version (\d+)\.(\d+)/) { + return undef; + } + $cmake_version = "$1.$2"; + return version->declare($cmake_version); +} + sub trace_filename { my $self = shift; return "$self->{obj_dir}/simx.fst" if $self->{trace_format} =~ /^fst/; diff --git a/test_regress/t/t_embed1.pl b/test_regress/t/t_embed1.pl index 9bdb42848..ee7ec7bc5 100755 --- a/test_regress/t/t_embed1.pl +++ b/test_regress/t/t_embed1.pl @@ -17,7 +17,7 @@ mkdir $child_dir; # Compile the child { - my @cmdargs = $Self->compile_vlt_flags + my @cmdargs = $Self->compile_vlt_cmd (VM_PREFIX => "$Self->{VM_PREFIX}_child", top_filename => "$Self->{name}_child.v", verilator_flags => ["-cc", "-Mdir", "${child_dir}", "--debug-check"], diff --git a/test_regress/t/t_flag_make_cmake.pl b/test_regress/t/t_flag_make_cmake.pl new file mode 100755 index 000000000..be0628665 --- /dev/null +++ b/test_regress/t/t_flag_make_cmake.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1); + +compile( + verilator_make_gmake => 0, + verilator_make_cmake => 1, + ); + + +my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt"; +if (! -e $cmakecache) { + error("$cmakecache does not exist") +} + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_make_cmake.v b/test_regress/t/t_flag_make_cmake.v new file mode 100644 index 000000000..51d5f55fe --- /dev/null +++ b/test_regress/t/t_flag_make_cmake.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_make_cmake_sc.pl b/test_regress/t/t_flag_make_cmake_sc.pl new file mode 100755 index 000000000..1ece57841 --- /dev/null +++ b/test_regress/t/t_flag_make_cmake_sc.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +# This test tests CMake support for SystemC + +scenarios(simulator => 1); + +compile( + verilator_make_gmake => 0, + verilator_make_cmake => 1, + verilator_flags2 => ["-sc"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_make_cmake_sc.v b/test_regress/t/t_flag_make_cmake_sc.v new file mode 100644 index 000000000..51d5f55fe --- /dev/null +++ b/test_regress/t/t_flag_make_cmake_sc.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/verilator-config-version.cmake.in b/verilator-config-version.cmake.in new file mode 100644 index 000000000..89862189a --- /dev/null +++ b/verilator-config-version.cmake.in @@ -0,0 +1,26 @@ +###################################################################### +# +# DESCRIPTION: CMake version configuration file for Verilator +# +# This allows specifying a minimum Verilator version. +# Include it in your CMakeLists.txt using: +# +# find_package(verilate 4.0) +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +set(PACKAGE_VERSION "@PACKAGE_VERSION@") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in new file mode 100644 index 000000000..0f25e3195 --- /dev/null +++ b/verilator-config.cmake.in @@ -0,0 +1,392 @@ +###################################################################### +# +# 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>) +# +# Copyright 2003-2019 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# +###################################################################### + +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 + HINTS ${VERILATOR_ROOT}/bin ENV VERILATOR_ROOT + NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) + +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 + PROPERTY VERILATOR_THREADED + BRIEF_DOCS "Verilator multithreading enabled" + FULL_DOCS "Verilator multithreading enabled" +) + +define_property(TARGET + PROPERTY VERILATOR_COVERAGE + BRIEF_DOCS "Verilator coverage enabled" + FULL_DOCS "Verilator coverage enabled" +) + +define_property(TARGET + PROPERTY VERILATOR_TRACE + BRIEF_DOCS "Verilator trace enabled" + FULL_DOCS "Verilator trace enabled" +) + +define_property(TARGET + PROPERTY VERILATOR_TRACE_VCD + BRIEF_DOCS "Verilator VCD trace enabled" + FULL_DOCS "Verilator VCD trace enabled" +) + +define_property(TARGET + PROPERTY VERILATOR_TRACE_FST + BRIEF_DOCS "Verilator FST trace enabled" + FULL_DOCS "Verilator FST trace enabled" +) + +define_property(TARGET + PROPERTY VERILATOR_SYSTEMC + BRIEF_DOCS "Verilator SystemC enabled" + FULL_DOCS "Verilator SystemC enabled" +) + +function(verilate TARGET) + cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC" + "PREFIX;TOP_MODULE;THREADS;DIRECTORY" + "SOURCES;VERILATOR_ARGS;INCLUDE_DIRS;OPT_SLOW;OPT_FAST" + ${ARGN}) + 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) + if (NOT COMPILER MATCHES "msvc|clang") + 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} + --prefix ${VERILATE_PREFIX} --Mdir ${VDIR} --make cmake + ${VERILATOR_ARGS} ${VERILATE_VERILATOR_ARGS} + ${VERILATE_SOURCES}) + + 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( + COMMAND ${VERILATOR_COMMAND} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE _VERILATOR_RC + OUTPUT_VARIABLE _VERILATOR_OUTPUT + ERROR_VARIABLE _VERILATOR_OUTPUT) + 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} + ${${VERILATE_PREFIX}_CLASSES_SLOW} + ${${VERILATE_PREFIX}_SUPPORT_FAST} + ${${VERILATE_PREFIX}_SUPPORT_SLOW}) + 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}" + COMMAND ${VERILATOR_COMMAND} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS "${VERILATOR_BIN}" ${${VERILATE_PREFIX}_DEPS} VERBATIM) + # Reconfigure if file list has changed + # (check contents rather than modified time to avoid unnecessary reconfiguration) + add_custom_command(OUTPUT "${VCMAKE_COPY}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${VCMAKE}" "${VCMAKE_COPY}" + DEPENDS "${VCMAKE}" VERBATIM) + + 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}" + ${${VERILATE_PREFIX}_GLOBAL} + ${${VERILATE_PREFIX}_USER_CLASSES}) + 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" + "${VERILATOR_ROOT}/include/vltstd") + target_compile_definitions(${TARGET} PRIVATE + VM_COVERAGE=$<BOOL:$<TARGET_PROPERTY:VERILATOR_COVERAGE>> + VM_SC=$<BOOL:$<TARGET_PROPERTY:VERILATOR_SYSTEMC>> + $<$<BOOL:$<TARGET_PROPERTY:VERILATOR_THREADED>>:VL_THREADED> + VM_TRACE=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE>> + VM_TRACE_VCD=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_VCD>> + VM_TRACE_FST=$<BOOL:$<TARGET_PROPERTY:VERILATOR_TRACE_FST>> + ) + + target_link_libraries(${TARGET} PUBLIC + ${${VERILATE_PREFIX}_USER_LDLIBS} + "$<$<BOOL:$<TARGET_PROPERTY:VERILATOR_THREADED>>:${VERILATOR_MT_CFLAGS}>" + ) + + # 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 + $<$<AND:${GEN_THREADED},$<NOT:${GEN_SYSTEMC}>>:cxx_std_11> + ) +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 + HINTS "${SYSTEMC_INCLUDE} " ENV SYSTEMC_INCLUDE) + find_path(SYSTEMC_INCLUDEDIR NAMES systemc.h + HINTS "${SYSTEMC_ROOT}" ENV SYSTEMC_ROOT + PATH_SUFFIXES include) + find_path(SYSTEMC_INCLUDEDIR NAMES systemc.h + HINTS "${SYSTEMC}" ENV SYSTEMC + PATH_SUFFIXES include) + + # 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 + HINTS "${SYSTEMC_LIBDIR}" ENV SYSTEMC_LIBDIR) + find_library(SYSTEMC_LIBRARY NAMES systemc + HINTS "${SYSTEMC_ROOT}" ENV SYSTEMC_ROOT + PATH_SUFFIXES lib) + find_library(SYSTEMC_LIBRARY NAMES systemc + HINTS "${SYSTEMC}" ENV SYSTEMC + PATH_SUFFIXES lib) + + if (SYSTEMC_INCLUDEDIR AND SYSTEMC_LIBRARY) + add_library(Verilator::systemc INTERFACE IMPORTED) + set_target_properties(Verilator::systemc + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SYSTEMC_INCLUDEDIR}" + INTERFACE_LINK_LIBRARIES "${SYSTEMC_LIBRARY}") + return() + endif() + + find_package(SystemCLanguage QUIET) + if (SystemCLanguage_FOUND) + add_library(Verilator::systemc INTERFACE IMPORTED) + set_target_properties(Verilator::systemc + PROPERTIES + INTERFACE_LINK_LIBRARIES "SystemC::systemc") + 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 + OUTPUT_VARIABLE KEY_VAL + RESULT_VARIABLE KEY_RET) + 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()