Add `--make json` to enable integration with non-make/cmake build systems (#5799)

This commit is contained in:
Andrew Voznytsa 2025-03-12 00:57:21 +01:00 committed by GitHub
parent 53151d7c5f
commit 6a48d3bb83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 603 additions and 5 deletions

View File

@ -19,6 +19,7 @@ Andreas Kuster
Andrei Kostovski
Andrew Miloradovsky
Andrew Nolte
Andrew Voznytsa
Anthony Donlon
Anthony Moore
Arkadiusz Kozdra

View File

@ -85,6 +85,7 @@ set(HEADERS
V3EmitCMain.h
V3EmitCMake.h
V3EmitMk.h
V3EmitMkJson.h
V3EmitV.h
V3EmitXml.h
V3Error.h
@ -246,6 +247,7 @@ set(COMMON_SOURCES
V3EmitCPch.cpp
V3EmitCSyms.cpp
V3EmitMk.cpp
V3EmitMkJson.cpp
V3EmitV.cpp
V3EmitXml.cpp
V3Error.cpp

View File

@ -253,6 +253,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3EmitCModel.o \
V3EmitCSyms.o \
V3EmitMk.o \
V3EmitMkJson.o \
V3EmitXml.o \
V3ExecGraph.o \
V3Expand.o \

317
src/V3EmitMkJson.cpp Normal file
View File

@ -0,0 +1,317 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Emit JSON manifest file
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2004-2025 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
//
//*************************************************************************
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3EmitMkJson.h"
#include "V3EmitCBase.h"
#include "V3HierBlock.h"
#include "V3Os.h"
#include <memory>
VL_DEFINE_DEBUG_FUNCTIONS;
// ######################################################################
// Emit statements
class V3EmitMkJsonEmitter final {
class Printer final {
// MEMBERS
private:
const std::unique_ptr<std::ofstream>& m_of;
std::stack<char>
m_scope; // Stack of ']' and '}' to be used to close currently open scopes
std::string m_prefix; // Prefix emitted before each line in the current scope (indent *
// scope depth)
std::string m_indent; // Single indent
bool m_empty = true; // Indicates that the current scope is empty
// METHODS
public:
Printer(const std::unique_ptr<std::ofstream>& of, const std::string& indent = " ")
: m_of(of)
, m_indent(indent) {
begin();
}
~Printer() { end(); }
Printer& begin(const std::string& name, char type = '{') {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << "\"" << name << "\": " << type << "\n";
m_prefix += m_indent;
m_scope.push(type == '{' ? '}' : ']');
m_empty = true;
return *this;
}
Printer& put(const std::string& name, const std::string& value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << "\"" << name << "\": \"" << value << "\"";
m_empty = false;
return *this;
}
Printer& put(const std::string& name, bool value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << "\"" << name << "\": " << (value ? "true" : "false");
m_empty = false;
return *this;
}
Printer& put(const std::string& name, int value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << "\"" << name << "\": " << value;
m_empty = false;
return *this;
}
Printer& begin(char type = '{') {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << type << "\n";
m_prefix += m_indent;
m_scope.push(type == '{' ? '}' : ']');
m_empty = true;
return *this;
}
Printer& put(const std::string& value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << "\"" << value << "\"";
m_empty = false;
return *this;
}
Printer& put(bool value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << (value ? "true" : "false");
m_empty = false;
return *this;
}
Printer& put(int value) {
if (!m_empty) *m_of << ",\n";
*m_of << m_prefix << value;
m_empty = false;
return *this;
}
template <typename T>
Printer& putList(const std::string& name, const T& list) {
if (list.empty()) return *this;
begin(name, '[');
for (auto it = list.begin(); it != list.end(); ++it) { put(*it); }
return end();
}
Printer& end() {
assert(m_prefix.length() >= m_indent.length());
m_prefix.erase(m_prefix.end() - m_indent.length(), m_prefix.end());
assert(!m_scope.empty());
*m_of << "\n" << m_prefix << m_scope.top();
m_scope.pop();
return *this;
}
Printer& operator+=(Printer& cursor) {
// Meaningless syntax sugar, at least for now
return *this;
}
};
// METHODS
// STATIC FUNCTIONS
static void emitManifest() {
const std::string makeDir
= V3Os::filenameSlashPath(V3Os::filenameRealPath(v3Global.opt.makeDir()));
const std::unique_ptr<std::ofstream> of{
V3File::new_ofstream(makeDir + "/" + v3Global.opt.prefix() + ".json")};
const string name = v3Global.opt.prefix();
const std::string trace
= v3Global.opt.trace() ? (v3Global.opt.traceFormat().vcd() ? "vcd" : "fst") : "off";
std::vector<string> classesFast;
std::vector<string> classesSlow;
std::vector<string> supportFast;
std::vector<string> supportSlow;
std::vector<string> global;
std::vector<string> deps;
std::vector<string> cppFiles;
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_AS(nodep->nextp(), NodeFile)) {
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()) {
const std::string filename
= V3Os::filenameSlashPath(V3Os::filenameRealPath(cfilep->name()));
if (cfilep->support()) {
if (cfilep->slow()) {
supportSlow.emplace_back(filename);
} else {
supportFast.emplace_back(filename);
}
} else {
if (cfilep->slow()) {
classesSlow.emplace_back(filename);
} else {
classesFast.emplace_back(filename);
}
}
}
}
const std::string verilatorRoot
= V3Os::filenameSlashPath(V3Os::filenameRealPath(V3Options::getenvVERILATOR_ROOT()));
global.emplace_back(verilatorRoot + "/include/verilated.cpp");
if (v3Global.dpi()) { global.emplace_back(verilatorRoot + "/include/verilated_dpi.cpp"); }
if (v3Global.opt.vpi()) {
global.emplace_back(verilatorRoot + "/include/verilated_vpi.cpp");
}
if (v3Global.opt.savable()) {
global.emplace_back(verilatorRoot + "/include/verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
global.emplace_back(verilatorRoot + "/include/verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
global.emplace_back(verilatorRoot + "/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
}
if (v3Global.usesProbDist()) {
global.emplace_back(verilatorRoot + "/include/verilated_probdist.cpp");
}
if (v3Global.usesTiming()) {
global.emplace_back(verilatorRoot + "/include/verilated_timing.cpp");
}
if (v3Global.useRandomizeMethods()) {
global.emplace_back(verilatorRoot + "/include/verilated_random.cpp");
}
global.emplace_back(verilatorRoot + "/include/verilated_threads.cpp");
if (v3Global.opt.usesProfiler()) {
global.emplace_back(verilatorRoot + "/include/verilated_profiler.cpp");
}
if (!v3Global.opt.libCreate().empty()) {
global.emplace_back(makeDir + "/" + v3Global.opt.libCreate() + ".cpp");
}
for (const auto& dep : V3File::getAllDeps())
deps.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(dep)));
for (const auto& cppFile : v3Global.opt.cppFiles())
cppFiles.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(cppFile)));
Printer manifest(of);
Printer& cursor = manifest.put("version", 1)
.begin("system")
.put("perl", V3Options::getenvPERL())
.put("python3", V3Options::getenvPYTHON3())
.put("verilator_root", verilatorRoot)
.put("verilator_solver", V3Options::getenvVERILATOR_SOLVER())
.end()
.begin("options")
.putList("cflags", v3Global.opt.cFlags())
.putList("ldflags", v3Global.opt.ldLibs())
.put("system_c", v3Global.opt.systemC())
.put("coverage", v3Global.opt.coverage())
.put("use_timing", v3Global.usesTiming())
.put("threads", v3Global.opt.threads())
.put("trace", trace)
.end()
.begin("sources")
.putList("global", global)
.putList("classes_slow", classesSlow)
.putList("classes_fast", classesFast)
.putList("support_slow", supportSlow)
.putList("support_fast", supportFast)
.putList("deps", deps)
.putList("user_classes", cppFiles)
.end();
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
// Sorted hierarchical blocks in order of leaf-first.
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
cursor += cursor.begin("submodules", '[');
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
it != hierBlocks.end(); ++it) {
const V3HierBlock* hblockp = *it;
const V3HierBlock::HierBlockSet& children = hblockp->children();
std::vector<std::string> deps;
std::vector<std::string> sources;
for (const auto& childr : children) {
deps.emplace_back((childr)->hierPrefix());
sources.emplace_back(makeDir + "/" + childr->hierWrapperFilename(true));
}
const string vFile = hblockp->vFileIfNecessary();
if (!vFile.empty()) { sources.emplace_back(vFile); }
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles)
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
std::vector<std::string> cflags;
cflags.emplace_back("-fPIC");
cursor += cursor.begin()
.put("prefix", hblockp->hierPrefix())
.put("top", hblockp->modp()->name())
.putList("deps", deps)
.put("directory", makeDir + "/" + hblockp->hierPrefix())
.putList("sources", sources)
.putList("cflags", cflags)
.put("verilator_args",
V3Os::filenameSlashPath(
V3Os::filenameRealPath(hblockp->commandArgsFilename(true))))
.end();
}
std::vector<std::string> sources;
for (const auto& itr : *planp)
sources.emplace_back(makeDir + "/" + itr.second->hierWrapperFilename(true));
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles)
sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(i)));
cursor += cursor.begin()
.put("prefix", v3Global.opt.prefix())
.put("top", v3Global.rootp()->topModulep()->name())
.put("directory", makeDir)
.putList("sources", sources)
.put("verilator_args", V3Os::filenameSlashPath(V3Os::filenameRealPath(
planp->topCommandArgsFilename(true))))
.end()
.end();
}
}
public:
explicit V3EmitMkJsonEmitter() { emitManifest(); }
virtual ~V3EmitMkJsonEmitter() = default;
};
void V3EmitMkJson::emit() {
UINFO(2, __FUNCTION__ << ": " << endl);
const V3EmitMkJsonEmitter emitter;
}

30
src/V3EmitMkJson.h Normal file
View File

@ -0,0 +1,30 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Emit JSON manifest file
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2025 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
//
//*************************************************************************
#ifndef VERILATOR_V3EMITMKJSON_H_
#define VERILATOR_V3EMITMKJSON_H_
#include "config_build.h"
#include "verilatedos.h"
//============================================================================
class V3EmitMkJson final {
public:
static void emit() VL_MT_DISABLED;
};
#endif // Guard

View File

@ -849,7 +849,7 @@ void V3Options::notify() VL_MT_DISABLED {
"--xml-only, --json-only or --E option");
}
if (m_build && (m_gmake || m_cmake)) {
if (m_build && (m_gmake || m_cmake || m_makeJson)) {
cmdfl->v3error("--make cannot be used together with --build. Suggest see manual");
}
@ -881,7 +881,7 @@ void V3Options::notify() VL_MT_DISABLED {
}
// Make sure at least one make system is enabled
if (!m_gmake && !m_cmake) m_gmake = true;
if (!m_gmake && !m_cmake && !m_makeJson) m_gmake = true;
if (m_hierarchical && (m_hierChild || !m_hierBlocks.empty())) {
cmdfl->v3error(
@ -1443,6 +1443,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
m_cmake = true;
} else if (!std::strcmp(valp, "gmake")) {
m_gmake = true;
} else if (!std::strcmp(valp, "json")) {
m_makeJson = true;
} else {
fl->v3fatal("Unknown --make system specified: '" << valp << "'");
}

View File

@ -261,6 +261,7 @@ private:
bool m_jsonOnly = false; // main switch: --json-only
bool m_lintOnly = false; // main switch: --lint-only
bool m_gmake = false; // main switch: --make gmake
bool m_makeJson = false; // main switch: --make json
bool m_main = false; // main switch: --main
bool m_outFormatOk = false; // main switch: --cc, --sc or --sp was specified
bool m_pedantic = false; // main switch: --Wpedantic
@ -527,6 +528,7 @@ public:
bool exe() const { return m_exe; }
bool flatten() const { return m_flatten; }
bool gmake() const { return m_gmake; }
bool makeJson() const { return m_makeJson; }
bool threadsDpiPure() const { return m_threadsDpiPure; }
bool threadsDpiUnpure() const { return m_threadsDpiUnpure; }
bool threadsCoarsen() const { return m_threadsCoarsen; }

View File

@ -310,6 +310,16 @@ bool V3Os::filenameIsRel(const string& filename) VL_PURE {
#endif
}
string V3Os::filenameSlashPath(const string& path) VL_PURE {
#if defined(_WIN32) || defined(__MINGW32__)
string slashedPath = path;
std::replace(slashedPath.begin(), slashedPath.end(), '\\', '/');
return slashedPath;
#else
return path;
#endif
}
//######################################################################
// File utilities

View File

@ -59,6 +59,8 @@ public:
static string filenameRelativePath(const string& filename, const string& base) VL_PURE;
///< @return filename is relative
static bool filenameIsRel(const string& filename) VL_PURE;
///< @return path slashed with '/'
static string filenameSlashPath(const string& filename) VL_PURE;
// METHODS (file utilities)
static string getline(std::istream& is, char delim = '\n');

View File

@ -46,6 +46,7 @@
#include "V3EmitCMain.h"
#include "V3EmitCMake.h"
#include "V3EmitMk.h"
#include "V3EmitMkJson.h"
#include "V3EmitV.h"
#include "V3EmitXml.h"
#include "V3ExecGraph.h"
@ -625,7 +626,7 @@ static void process() {
if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() && !v3Global.opt.dpiHdrOnly()) {
if (v3Global.opt.main()) V3EmitCMain::emit();
// V3EmitMk/V3EmitCMake must be after all other emitters,
// V3EmitMk/V3EmitCMake/V3EmitMkJson must be after all other emitters,
// as they and below code visits AstCFiles added earlier
size_t src_f_cnt = 0;
for (AstNode* nodep = v3Global.rootp()->filesp(); nodep; nodep = nodep->nextp()) {
@ -634,6 +635,7 @@ static void process() {
}
if (src_f_cnt >= V3EmitMk::PARALLEL_FILE_CNT_THRESHOLD) v3Global.useParallelBuild(true);
if (v3Global.opt.cmake()) V3EmitCMake::emit();
if (v3Global.opt.makeJson()) V3EmitMkJson::emit();
if (v3Global.opt.gmake()) V3EmitMk::emitmk();
}
@ -734,6 +736,10 @@ static void verilate(const string& argString) {
v3Global.hierPlanp()->writeCommandArgsFiles(true);
V3EmitCMake::emit();
}
if (v3Global.opt.makeJson()) {
v3Global.hierPlanp()->writeCommandArgsFiles(true);
V3EmitMkJson::emit();
}
v3Global.hierPlanp()->writeParametersFiles();
}
if (v3Global.opt.makeDepend().isTrue()) {

View File

@ -0,0 +1,29 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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
import vltest_bootstrap
test.scenarios('simulator')
test.top_filename = "t/t_flag_make_cmake.v"
test.compile(verilator_flags2=['--make json'],
verilator_make_gmake=False, verilator_make_cmake=False)
nout = test.run_capture("jq --version", check=False)
version_match = re.search(r'jq-([0-9.]+)', nout, re.IGNORECASE)
if not version_match:
test.skip("jq is not installed")
json_filename = test.obj_dir + "/" + test.vm_prefix + ".json"
if not os.path.exists(json_filename):
test.error(json_filename + " does not exist")
test.run(cmd=['cat "' + json_filename + '" | jq ".version"'])
test.passes()

View File

@ -19,7 +19,7 @@
#
######################################################################
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.19)
# Prefer VERILATOR_ROOT from environment
if(DEFINED ENV{VERILATOR_ROOT})
@ -163,6 +163,81 @@ define_property(
FULL_DOCS "Verilator trace structs enabled"
)
function(json_get_string RET JSON SECTION VARIABLE)
string(JSON JV ERROR_VARIABLE STATUS GET "${JSON}" ${SECTION} ${VARIABLE})
if (NOT ${STATUS} STREQUAL "NOTFOUND")
set(JV "")
endif()
set(${RET} ${JV} PARENT_SCOPE)
endfunction()
function(json_get_bool RET JSON SECTION VARIABLE)
string(JSON JV GET "${JSON}" ${SECTION} ${VARIABLE})
if(JV)
set(${RET} 1 PARENT_SCOPE)
else()
set(${RET} 0 PARENT_SCOPE)
endif()
endfunction()
function(json_get_int RET JSON SECTION VARIABLE)
string(JSON JV GET "${JSON}" ${SECTION} ${VARIABLE})
set(${RET} ${JV} PARENT_SCOPE)
endfunction()
function(json_get_trace RET_VCD RET_FST JSON SECTION VARIABLE)
string(JSON JV GET "${JSON}" ${SECTION} ${VARIABLE})
if(JV STREQUAL "vcd")
set(${RET_VCD} 1 PARENT_SCOPE)
set(${RET_FST} 0 PARENT_SCOPE)
elseif(JV STREQUAL "fst")
set(${RET_VCD} 0 PARENT_SCOPE)
set(${RET_FST} 1 PARENT_SCOPE)
else()
set(${RET_VCD} 0 PARENT_SCOPE)
set(${RET_FST} 0 PARENT_SCOPE)
endif()
endfunction()
function(json_get_submodules SUBMODULES NSUBMODULES JSON)
string(JSON JV ERROR_VARIABLE STATUS GET "${JSON}" submodules)
if (NOT ${STATUS} STREQUAL "NOTFOUND")
set(${SUBMODULES} "" PARENT_SCOPE)
set(${NSUBMODULES} 0 PARENT_SCOPE)
return()
endif()
string(JSON L ERROR_VARIABLE STATUS LENGTH "${JSON}" submodules)
math(EXPR L "${L}-1")
set(${SUBMODULES} ${JV} PARENT_SCOPE)
set(${NSUBMODULES} ${L} PARENT_SCOPE)
endfunction()
function(json_get_list RET JSON SECTION VARIABLE)
string(JSON L ERROR_VARIABLE STATUS LENGTH "${JSON}" ${SECTION} ${VARIABLE})
if (NOT ${STATUS} STREQUAL "NOTFOUND" OR NOT ${L})
set(${RET} "" PARENT_SCOPE)
return()
endif()
math(EXPR L "${L}-1")
foreach(I RANGE ${L})
string(JSON JV GET "${JSON}" ${SECTION} ${VARIABLE} ${I})
if(NOT JL)
string(APPEND JL "${JV}")
else()
string(APPEND JL " ${JV}")
endif()
endforeach()
set(${RET} ${JL} PARENT_SCOPE)
endfunction()
function(verilate TARGET)
cmake_parse_arguments(
VERILATE
@ -294,7 +369,7 @@ function(verilate TARGET)
--Mdir
${VDIR}
--make
cmake
json
${VERILATOR_ARGS}
${VERILATE_VERILATOR_ARGS}
${VERILATE_SOURCES}
@ -337,6 +412,127 @@ function(verilate TARGET)
"Verilator command failed (return code=${_VERILATOR_RC})"
)
endif()
file(READ ${VDIR}/${VERILATE_PREFIX}.json MANIFEST)
json_get_string(JSYSTEM_PERL "${MANIFEST}" system perl)
json_get_string(JSYSTEM_PYTHON3 "${MANIFEST}" system python3)
json_get_string(JSYSTEM_VERILATOR_ROOT "${MANIFEST}" system verilator_root)
json_get_string(JSYSTEM_VERILATOR_SOLVER "${MANIFEST}" system verilator_solver)
json_get_list(JOPTIONS_CFLAGS "${MANIFEST}" options cflags)
json_get_list(JOPTIONS_LDFLAGS "${MANIFEST}" options ldflags)
json_get_bool(JOPTIONS_SYSTEM_C "${MANIFEST}" options system_c)
json_get_bool(JOPTIONS_COVERAGE "${MANIFEST}" options coverage)
json_get_bool(JOPTIONS_USE_TIMING "${MANIFEST}" options use_timing)
json_get_int(JOPTIONS_THREADS "${MANIFEST}" options threads)
json_get_trace(JOPTIONS_TRACE_VCD JOPTIONS_TRACE_FST "${MANIFEST}" options trace)
json_get_list(JSOURCES_GLOBAL "${MANIFEST}" sources global)
json_get_list(JSOURCES_CLASSES_SLOW "${MANIFEST}" sources classes_slow)
json_get_list(JSOURCES_CLASSES_FAST "${MANIFEST}" sources classes_fast)
json_get_list(JSOURCES_SUPPORT_SLOW "${MANIFEST}" sources support_slow)
json_get_list(JSOURCES_SUPPORT_FAST "${MANIFEST}" sources support_fast)
json_get_list(JSOURCES_USER_CLASSES "${MANIFEST}" sources user_classes)
file(WRITE ${VDIR}/${VERILATE_PREFIX}.cmake
"# Verilated -*- CMake -*-\n"
"# DESCRIPTION: Verilator output: CMake include script with class lists\n"
"#\n"
"# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n"
"# This file is meant to be consumed by the verilate() function,\n"
"# which becomes available after executing `find_package(verilator).\n\n"
"### Constants...\n"
"set(PERL \"${JSYSTEM_PERL}\" CACHE FILEPATH \"Perl executable (from \$PERL, defaults to 'perl' if not set)\")\n"
"set(PYTHON3 \"${JSYSTEM_PYTHON3}\" CACHE FILEPATH \"Python3 executable (from \$PYTHON3, defaults to 'python3' if not set)\")\n"
"set(VERILATOR_ROOT \"${JSYSTEM_VERILATOR_ROOT}\" CACHE PATH \"Path to Verilator kit (from $VERILATOR_ROOT)\")\n"
"set(VERILATOR_SOLVER \"${JSYSTEM_VERILATOR_SOLVER}\" CACHE STRING \"Default SMT solver for constrained randomization (from \$VERILATOR_SOLVER)\")\n\n"
"### Compiler flags...\n"
"# User CFLAGS (from -CFLAGS on Verilator command line)\n"
"set(${VERILATE_PREFIX}_USER_CFLAGS ${JOPTIONS_CFLAGS})\n"
"# User LDLIBS (from -LDFLAGS on Verilator command line)\n"
"set(${VERILATE_PREFIX}_USER_LDLIBS ${JOPTIONS_LDFLAGS})\n\n"
"### Switches...\n"
"# SystemC output mode? 0/1 (from --sc)\n"
"set(${VERILATE_PREFIX}_SC ${JOPTIONS_SYSTEM_C})\n"
"# Coverage output mode? 0/1 (from --coverage)\n"
"set(${VERILATE_PREFIX}_COVERAGE ${JOPTIONS_COVERAGE})\n"
"# Timing mode? 0/1\n"
"set(${VERILATE_PREFIX}_TIMING ${JOPTIONS_USE_TIMING})\n"
"# Threaded output mode? 1/N threads (from --threads)\n"
"set(${VERILATE_PREFIX}_THREADS ${JOPTIONS_THREADS})\n"
"# VCD Tracing output mode? 0/1 (from --trace)\n"
"set(${VERILATE_PREFIX}_TRACE_VCD ${JOPTIONS_TRACE_VCD})\n"
"# FST Tracing output mode? 0/1 (from --trace-fst)\n"
"set(${VERILATE_PREFIX}_TRACE_FST ${JOPTIONS_TRACE_FST})\n\n"
"### Sources...\n"
"# Global classes, need linked once per executable\n"
"set(${VERILATE_PREFIX}_GLOBAL ${JSOURCES_GLOBAL})\n"
"# Generated module classes, non-fast-path, compile with low/medium optimization\n"
"set(${VERILATE_PREFIX}_CLASSES_SLOW ${JSOURCES_CLASSES_SLOW})\n"
"# Generated module classes, fast-path, compile with highest optimization\n"
"set(${VERILATE_PREFIX}_CLASSES_FAST ${JSOURCES_CLASSES_FAST})\n"
"# Generated support classes, non-fast-path, compile with low/medium optimization\n"
"set(${VERILATE_PREFIX}_SUPPORT_SLOW ${JSOURCES_SUPPORT_SLOW})\n"
"# Generated support classes, fast-path, compile with highest optimization\n"
"set(${VERILATE_PREFIX}_SUPPORT_FAST ${JSOURCES_SUPPORT_FAST})\n"
"# All dependencies\n"
"set(${VERILATE_PREFIX}_DEPS ${JSOURCES_DEPS})\n"
"# User .cpp files (from .cpp's on Verilator command line)\n"
"set(${VERILATE_PREFIX}_USER_CLASSES ${JSOURCES_USER_CLASSES})\n"
)
json_get_submodules(JSUBMODULES JNSUBMODULES "${MANIFEST}")
if (JNSUBMODULES)
file(APPEND ${VDIR}/${VERILATE_PREFIX}.cmake
"# Verilate hierarchical blocks\n"
"get_target_property(TOP_TARGET_NAME \"\${TARGET}\" NAME)\n"
)
foreach(I RANGE ${JNSUBMODULES})
json_get_string(JSUBMODULE_PREFIX "${JSUBMODULES}" ${I} prefix)
json_get_string(JSUBMODULE_TOP "${JSUBMODULES}" ${I} top)
json_get_list(JSUBMODULE_DEPS "${JSUBMODULES}" ${I} deps)
json_get_string(JSUBMODULE_DIRECTORY "${JSUBMODULES}" ${I} directory)
json_get_list(JSUBMODULE_SOURCES "${JSUBMODULES}" ${I} sources)
json_get_list(JSUBMODULE_CFLAGS "${JSUBMODULES}" ${I} cflags)
json_get_string(JSUBMODILE_VERILATOR_ARGS "${JSUBMODULES}" ${I} verilator_args)
set(SUBMODULE_CMAKE "")
set(SUBMODULE_VERILATE_ARGS "")
if (NOT ${I} STREQUAL ${JNSUBMODULES})
string(APPEND SUBMODULE_CMAKE
"add_library(${JSUBMODULE_PREFIX} STATIC)\n"
"target_link_libraries(\${TOP_TARGET_NAME} PRIVATE ${JSUBMODULE_PREFIX})\n"
)
if (JSUBMODULE_DEPS)
string(APPEND SUBMODULE_CMAKE "target_link_libraries(${JSUBMODULE_PREFIX} INTERFACE ${JSUBMODULE_DEPS})\n")
endif()
string(APPEND SUBMODULE_VERILATE_ARGS "${JSUBMODULE_PREFIX} PREFIX ${JSUBMODULE_PREFIX} TOP_MODULE ${JSUBMODULE_TOP} DIRECTORY ${JSUBMODULE_DIRECTORY} SOURCES ${JSUBMODULE_SOURCES}")
else()
string(APPEND SUBMODULE_CMAKE "# Verilate the top module that refers to lib-create wrappers of above\n")
string(APPEND SUBMODULE_VERILATE_ARGS "\${TOP_TARGET_NAME} PREFIX ${JSUBMODULE_PREFIX} TOP_MODULE ${JSUBMODULE_TOP} DIRECTORY ${JSUBMODULE_DIRECTORY} SOURCES ${JSUBMODULE_SOURCES}")
endif()
if (JSUBMODILE_VERILATOR_ARGS)
string(APPEND SUBMODULE_VERILATE_ARGS " VERILATOR_ARGS -f ${JSUBMODILE_VERILATOR_ARGS}")
endif()
if (JSUBMODULE_CFLAGS)
string(APPEND SUBMODULE_VERILATE_ARGS " -CFLAGS ${JSUBMODULE_CFLAGS}")
endif()
file(APPEND ${VDIR}/${VERILATE_PREFIX}.cmake
"${SUBMODULE_CMAKE}"
"verilate(${SUBMODULE_VERILATE_ARGS})\n"
)
endforeach()
endif()
execute_process(
COMMAND "${CMAKE_COMMAND}" -E copy "${VCMAKE}" "${VCMAKE_COPY}"
)