diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 4c97a82e4..49837598b 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -35,6 +35,12 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@ CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@ # Compiler flags that enable coroutine support CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@ +# Compiler flags when creating a precompiled header +CFG_CXXFLAGS_PCH = -x c++-header +# Compiler option to put in front of filename to read precompiled header +CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@ +# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC +CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@ # Linker flags CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@ # Linker libraries for multithreading @@ -47,6 +53,12 @@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage VERILATOR_INCLUDER = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_includer VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report +###################################################################### +# CCACHE flags (via environment as no command line option available) + +CCACHE_SLOPPINESS ?= pch_defines,time_macros +export CCACHE_SLOPPINESS + ###################################################################### # Make checks @@ -166,11 +178,17 @@ endif VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST) VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW) +# Precompiled header filename +VK_PCH_H = $(VM_PREFIX)__pch.h +# Compiler read-a-precompiled-header option for precompiled header filename +VK_PCH_I_FAST = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.fast$(CFG_GCH_IF_CLANG) +VK_PCH_I_SLOW = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.slow$(CFG_GCH_IF_CLANG) + ####################################################################### ### Overall Objects Linking -VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST)) -VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW)) +VK_OBJS_FAST = $(addsuffix .o, $(VM_FAST)) +VK_OBJS_SLOW = $(addsuffix .o, $(VM_SLOW)) VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES)) @@ -197,7 +215,7 @@ else # Parallel build: Each .cpp file by itself. This can be somewhat slower for # very small designs and examples, but is a lot faster for large designs. - VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS) + VK_OBJS += $(VK_OBJS_FAST) $(VK_OBJS_SLOW) endif # When archiving just objects (.o), use single $(AR) run @@ -241,18 +259,30 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS) ### Compile rules ifneq ($(VM_DEFAULT_RULES),0) -# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o +# Anything not in $(VK_OBJS_SLOW) or $(VK_GLOBAL_OBJS), including verilated.o # and user files passed on the Verilator command line use this rule. # We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to # allow USER_CPPFLAGS to override them %.o: %.cpp $(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< -$(VK_SLOW_OBJS): %.o: %.cpp - $(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +$(VK_OBJS_FAST): %.o: %.cpp $(VK_PCH_H).fast.gch + $(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_FAST) -c -o $@ $< + +$(VK_OBJS_SLOW): %.o: %.cpp $(VK_PCH_H).slow.gch + $(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_SLOW) -c -o $@ $< $(VK_GLOBAL_OBJS): %.o: %.cpp $(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< + +# Precompile a header file +# PCH's compiler flags must match exactly the fast/slow arguments used in the .cpp file, +# or the PCH file won't be used. +%.fast.gch: % + $(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@ +%.slow.gch: % + $(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@ + endif #Default rule embedded in make: @@ -300,19 +330,21 @@ endif debug-make:: @echo - @echo CXXFLAGS: $(CXXFLAGS) @echo CPPFLAGS: $(CPPFLAGS) + @echo CXXFLAGS: $(CXXFLAGS) @echo OPT_FAST: $(OPT_FAST) @echo OPT_SLOW: $(OPT_SLOW) - @echo VM_PREFIX: $(VM_PREFIX) - @echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS) + @echo VK_OBJS: $(VK_OBJS) + @echo VK_OBJS_FAST: $(VK_OBJS_FAST) + @echo VK_OBJS_SLOW: $(VK_OBJS_SLOW) @echo VM_CLASSES_FAST: $(VM_CLASSES_FAST) @echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW) - @echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST) - @echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW) @echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST) @echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW) - @echo VK_OBJS: $(VK_OBJS) + @echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS) + @echo VM_PREFIX: $(VM_PREFIX) + @echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST) + @echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW) @echo ###################################################################### diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f31871b65..8124e0ee3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -228,6 +228,7 @@ set(COMMON_SOURCES V3EmitCMain.cpp V3EmitCMake.cpp V3EmitCModel.cpp + V3EmitCPch.cpp V3EmitCSyms.cpp V3EmitMk.cpp V3EmitV.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4efc14c87..8c79c0066 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -193,6 +193,7 @@ RAW_OBJS_PCH_ASTMT = \ V3EmitCHeaders.o \ V3EmitCImp.o \ V3EmitCInlines.o \ + V3EmitCPch.o \ V3EmitV.o \ V3File.o \ V3Global.o \ diff --git a/src/V3EmitC.h b/src/V3EmitC.h index 4ee9460cf..bbca3be0d 100644 --- a/src/V3EmitC.h +++ b/src/V3EmitC.h @@ -27,12 +27,13 @@ class V3EmitC final { public: static void emitcConstPool() VL_MT_DISABLED; + static void emitcFiles() VL_MT_DISABLED; static void emitcHeaders() VL_MT_DISABLED; static void emitcImp(); static void emitcInlines() VL_MT_DISABLED; static void emitcModel() VL_MT_DISABLED; + static void emitcPch() VL_MT_DISABLED; static void emitcSyms(bool dpiHdrOnly = false) VL_MT_DISABLED; - static void emitcFiles() VL_MT_DISABLED; }; #endif // Guard diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 5abf33271..7067f8ed6 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -55,6 +55,7 @@ public: return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className + "*>(voidSelf);\n"; } + static string pchClassName() VL_MT_STABLE { return v3Global.opt.prefix() + "__pch"; } static string symClassName() VL_MT_STABLE { return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms"); } @@ -62,6 +63,9 @@ public: static string symClassAssign() { return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } + static string topClassName() VL_MT_SAFE { // Return name of top wrapper module + return v3Global.opt.prefix(); + } static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); } @@ -104,9 +108,6 @@ public: return v3Global.opt.protectIds() ? "" : in; } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); - static string topClassName() VL_MT_SAFE { // Return name of top wrapper module - return v3Global.opt.prefix(); - } static AstCFile* newCFile(const string& filename, bool slow, bool source); static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE; string cFuncArgs(const AstCFunc* nodep); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index e640634c9..e20320052 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -190,11 +190,8 @@ class EmitCImp final : EmitCFunc { puts("// DESCRIPTION: Verilator output: Design implementation internals\n"); puts("// See " + topClassName() + ".h for the primary calling header\n"); - // Include files - puts("\n#include \"verilated.h\"\n"); - if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n"); puts("\n"); - puts("#include \"" + symClassName() + ".h\"\n"); + puts("#include \"" + pchClassName() + ".h\"\n"); for (const string& name : headers) puts("#include \"" + name + ".h\"\n"); emitTextSection(m_modp, VNType::atScImpHdr); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 53c5339fb..5abad82d7 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -627,14 +627,10 @@ class EmitCModel final : public EmitCFunc { "Model implementation (design independent parts)\n"); puts("\n"); - puts("#include \"" + topClassName() + ".h\"\n"); - puts("#include \"" + symClassName() + ".h\"\n"); + puts("#include \"" + pchClassName() + ".h\"\n"); if (v3Global.opt.trace()) { puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); } - if (v3Global.dpi()) { // - puts("#include \"verilated_dpi.h\"\n"); - } emitConstructorImplementation(modp); emitDestructorImplementation(); diff --git a/src/V3EmitCPch.cpp b/src/V3EmitCPch.cpp new file mode 100644 index 000000000..1cd6ed965 --- /dev/null +++ b/src/V3EmitCPch.cpp @@ -0,0 +1,73 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// Code available from: https://verilator.org +// +// Copyright 2003-2023 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. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// DESCRIPTION: Verilator: Emit C++ for precompiled header include +// + +#include "V3PchAstMT.h" + +#include "V3EmitC.h" +#include "V3EmitCBase.h" +#include "V3File.h" + +VL_DEFINE_DEBUG_FUNCTIONS; + +//###################################################################### +// Precompiled header emitter + +class EmitCPch final : EmitCBase { +public: + // METHODS + + void emitPch() { + // Generate the makefile + V3OutCFile of{v3Global.opt.makeDir() + "/" + pchClassName() + ".h"}; + of.putsHeader(); + of.puts("// DESCRIPTION: Verilator output: Precompiled header\n"); + of.puts("//\n"); + of.puts("// Internal details; most user sources do not need this header,\n"); + of.puts("// unless using verilator public meta comments.\n"); + of.puts("// Suggest use " + topClassName() + ".h instead.\n"); + of.puts("\n"); + + of.putsGuard(); + + of.puts("\n"); + of.puts("// GCC and Clang only will precompile headers (PCH) for the first header.\n"); + of.puts("// So, make sure this is the one and only PCH.\n"); + of.puts("// If multiple module's includes are needed, use individual includes.\n"); + of.puts("#ifdef VL_PCH_INCLUDED\n"); + of.puts("# error \"Including multiple precompiled header files\"\n"); + of.puts("#endif\n"); + of.puts("#define VL_PCH_INCLUDED\n"); + + of.puts("\n"); + of.puts("\n#include \"verilated.h\"\n"); + if (v3Global.dpi()) of.puts("#include \"verilated_dpi.h\"\n"); + + of.puts("\n"); + of.puts("#include \"" + symClassName() + ".h\"\n"); + of.puts("#include \"" + topClassName() + ".h\"\n"); + + of.putsEndGuard(); + } + +public: + explicit EmitCPch() { emitPch(); } +}; + +//###################################################################### +// EmitC static functions + +void V3EmitC::emitcPch() { + UINFO(2, __FUNCTION__ << ": " << endl); + EmitCPch{}; +} diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 4642ac016..8ac652a4b 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -606,7 +606,7 @@ void EmitCSyms::emitSymImpPreamble() { puts("\n"); // Includes - puts("#include \"" + symClassName() + ".h\"\n"); + puts("#include \"" + pchClassName() + ".h\"\n"); puts("#include \"" + topClassName() + ".h\"\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_AS(nodep->nextp(), NodeModule)) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index e5ba41c55..1a4c0bdc6 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -559,6 +559,7 @@ static void process() { V3EmitC::emitcSyms(); V3EmitC::emitcConstPool(); V3EmitC::emitcModel(); + V3EmitC::emitcPch(); V3EmitC::emitcHeaders(); } else if (v3Global.opt.dpiHdrOnly()) { V3EmitC::emitcSyms(true); diff --git a/test_regress/t/t_trace_noflag_bad.out b/test_regress/t/t_trace_noflag_bad.out index e8156e0c9..66a2974a8 100644 --- a/test_regress/t/t_trace_noflag_bad.out +++ b/test_regress/t/t_trace_noflag_bad.out @@ -1,2 +1,2 @@ -%Error: Vt_trace_noflag_bad.cpp:106: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option +%Error: Vt_trace_noflag_bad.cpp:105: 'Vt_trace_noflag_bad::trace()' called on model that was Verilated without --trace option Aborting...