// -*- 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 VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### // Emit statements class V3EmitMkJsonEmitter final { // METHODS // STATIC FUNCTIONS static void emitManifest() { const std::string makeDir = V3Os::filenameSlashPath(V3Os::filenameRealPath(v3Global.opt.makeDir())); V3OutJsonFile of{makeDir + "/" + v3Global.opt.prefix() + ".json"}; std::vector classesFast; std::vector classesSlow; std::vector supportFast; std::vector supportSlow; std::vector global; std::vector deps; std::vector 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())); for (const string& cpp : v3Global.verilatedCppFiles()) global.emplace_back(verilatorRoot + "/include/" + 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))); of.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", v3Global.opt.trace()) .put("trace_fst", v3Global.opt.traceEnabledFst()) .put("trace_saif", v3Global.opt.traceEnabledSaif()) .put("trace_vcd", v3Global.opt.traceEnabledVcd()) .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 V3HierGraph* const graphp = v3Global.hierGraphp()) { of.begin("submodules", '['); // Enumerate in dependency order, leaves first. TODO: Shouldn't // really have to, but verilator-config.cmake.in depends on order. for (const V3GraphVertex& vtx : vlstd::reverse_view(graphp->vertices())) { const V3HierBlock* const hblockp = vtx.as(); std::vector hierDeps; std::vector sources; for (const V3GraphEdge& edge : hblockp->outEdges()) { const V3HierBlock* const dependencyp = edge.top()->as(); hierDeps.emplace_back(dependencyp->hierPrefix()); sources.emplace_back(makeDir + "/" + dependencyp->hierWrapperFilename(true)); } const std::string vFile = hblockp->vFileIfNecessary(); if (!vFile.empty()) sources.emplace_back(vFile); for (const VFileLibName& i : v3Global.opt.vFiles()) { const std::string fname = i.filename(); sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(fname))); } of.begin() .put("prefix", hblockp->hierPrefix()) .put("top", hblockp->modp()->name()) .putList("deps", hierDeps) .put("directory", makeDir + "/" + hblockp->hierPrefix()) .putList("sources", sources) .putList("cflags", {"-fPIC"}) .put("verilator_args", V3Os::filenameSlashPath(V3Os::filenameRealPath( hblockp->commandArgsFilename(true)))) .end(); } // Top level reintegration { // TODO: When this reintegration "submodule" is built with the bundled // CMake script, it will overwrite the original json manifest containing the // "subodule" list we are creating here with one that doesn't have "submodule". // Good luck debugging, suggest 'message(${MANIFEST})' in verilated-config.cmake. std::vector sources; for (const V3GraphVertex& vtx : graphp->vertices()) { const V3HierBlock* const blockp = vtx.as(); sources.emplace_back(makeDir + "/" + blockp->hierWrapperFilename(true)); } for (const VFileLibName& i : v3Global.opt.vFiles()) { const std::string fname = i.filename(); sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(fname))); } of.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( graphp->topCommandArgsFilename(true)))) .end(); } of.end(); // submodules } } public: explicit V3EmitMkJsonEmitter() { emitManifest(); } virtual ~V3EmitMkJsonEmitter() = default; }; void V3EmitMkJson::emit() { UINFO(2, __FUNCTION__ << ":"); const V3EmitMkJsonEmitter emitter; }