Internals: Use a V3Graph for the hierarchical plan (#6545)
I stared this because the emitted makefiles for hierarchical verilation were non-deterministic (iterating unordered_map indexed by pointers). Then I realized that the V3HierPlan is just a dependency graph encoded in a slightly idiosyncratic way. We do have a data structure to use for that instead. With that the output should always be deterministic + have nicer dumps.
This commit is contained in:
parent
e63d486422
commit
9dc0cf5a7c
|
|
@ -179,30 +179,30 @@ class CMakeEmitter final {
|
|||
|
||||
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
|
||||
cmake_set_raw(*of, name + "_USER_CLASSES", cmake_list(v3Global.opt.cppFiles()));
|
||||
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
|
||||
if (const V3HierGraph* const graphp = v3Global.hierGraphp()) {
|
||||
*of << "# Verilate hierarchical blocks\n";
|
||||
// Sorted hierarchical blocks in order of leaf-first.
|
||||
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
||||
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
|
||||
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
||||
it != hierBlocks.end(); ++it) {
|
||||
const V3HierBlock* hblockp = *it;
|
||||
const V3HierBlock::HierBlockSet& children = hblockp->children();
|
||||
for (const V3GraphVertex& vtx : vlstd::reverse_view(graphp->vertices())) {
|
||||
const V3HierBlock* const hblockp = vtx.as<V3HierBlock>();
|
||||
const string prefix = hblockp->hierPrefix();
|
||||
*of << "add_library(" << prefix << " STATIC)\n";
|
||||
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
|
||||
if (!children.empty()) {
|
||||
if (!hblockp->outEmpty()) {
|
||||
*of << "target_link_libraries(" << prefix << " INTERFACE";
|
||||
for (const V3HierBlock* const childp : children) {
|
||||
*of << " " << childp->hierPrefix();
|
||||
for (const V3GraphEdge& edge : hblockp->outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
*of << " " << dependencyp->hierPrefix();
|
||||
}
|
||||
*of << ")\n";
|
||||
}
|
||||
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
|
||||
<< hblockp->modp()->name() << " DIRECTORY "
|
||||
<< v3Global.opt.makeDir() + "/" + prefix << " SOURCES ";
|
||||
for (const V3HierBlock* const childp : children) {
|
||||
*of << " " << v3Global.opt.makeDir() + "/" + childp->hierWrapperFilename(true);
|
||||
for (const V3GraphEdge& edge : hblockp->outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
*of << " "
|
||||
<< v3Global.opt.makeDir() + "/" + dependencyp->hierWrapperFilename(true);
|
||||
}
|
||||
*of << " ";
|
||||
const string vFile = hblockp->vFileIfNecessary();
|
||||
|
|
@ -219,12 +219,13 @@ class CMakeEmitter final {
|
|||
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
|
||||
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
||||
<< v3Global.opt.makeDir() << " SOURCES ";
|
||||
for (const auto& itr : *planp) {
|
||||
*of << " " << v3Global.opt.makeDir() + "/" + itr.second.hierWrapperFilename(true);
|
||||
for (const V3GraphVertex& vtx : graphp->vertices()) {
|
||||
const V3HierBlock* const hblockp = vtx.as<V3HierBlock>();
|
||||
*of << " " << v3Global.opt.makeDir() + "/" + hblockp->hierWrapperFilename(true);
|
||||
}
|
||||
*of << " " << cmake_list(v3Global.opt.vFiles());
|
||||
*of << " VERILATOR_ARGS ";
|
||||
*of << "-f " << planp->topCommandArgsFilename(true);
|
||||
*of << "-f " << graphp->topCommandArgsFilename(true);
|
||||
*of << ")\n";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -803,7 +803,7 @@ public:
|
|||
//######################################################################
|
||||
|
||||
class EmitMkHierVerilation final {
|
||||
const V3HierBlockPlan* const m_planp;
|
||||
const V3HierGraph* const m_graphp;
|
||||
const string m_makefile; // path of this makefile
|
||||
void emitCommonOpts(V3OutMkFile& of) const {
|
||||
const string cwd = V3Os::filenameRealPath(".");
|
||||
|
|
@ -843,11 +843,9 @@ class EmitMkHierVerilation final {
|
|||
|
||||
of.puts("# Libraries of hierarchical blocks\n");
|
||||
of.puts("VM_HIER_LIBS := \\\n");
|
||||
const V3HierBlockPlan::HierVector blocks
|
||||
= m_planp->hierBlocksSorted(); // leaf comes first
|
||||
// List in order of leaf-last order so that linker can resolve dependency
|
||||
for (const auto& block : vlstd::reverse_view(blocks)) {
|
||||
of.puts(" " + block->hierLibFilename(true) + " \\\n");
|
||||
for (const V3GraphVertex& vtx : m_graphp->vertices()) {
|
||||
const V3HierBlock* const blockp = vtx.as<V3HierBlock>();
|
||||
of.puts(" " + blockp->hierLibFilename(true) + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
|
|
@ -866,28 +864,31 @@ class EmitMkHierVerilation final {
|
|||
|
||||
// Top level module
|
||||
{
|
||||
const string argsFile = v3Global.hierPlanp()->topCommandArgsFilename(false);
|
||||
const string argsFile = v3Global.hierGraphp()->topCommandArgsFilename(false);
|
||||
of.puts("\n# Verilate the top module\n");
|
||||
of.puts(v3Global.opt.prefix()
|
||||
+ ".mk: $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
|
||||
of.puts(V3Os::filenameNonDir(argsFile) + " ");
|
||||
for (const auto& itr : *m_planp) of.puts(itr.second.hierWrapperFilename(true) + " ");
|
||||
for (const V3GraphVertex& vtx : m_graphp->vertices()) {
|
||||
const V3HierBlock* const blockp = vtx.as<V3HierBlock>();
|
||||
of.puts(blockp->hierWrapperFilename(true) + " ");
|
||||
}
|
||||
of.puts("\n");
|
||||
emitLaunchVerilator(of, argsFile);
|
||||
}
|
||||
|
||||
// Rules to process hierarchical blocks
|
||||
of.puts("\n# Verilate hierarchical blocks\n");
|
||||
for (const V3HierBlock* const blockp : m_planp->hierBlocksSorted()) {
|
||||
for (const V3GraphVertex& vtx : m_graphp->vertices()) {
|
||||
const V3HierBlock* const blockp = vtx.as<V3HierBlock>();
|
||||
const string prefix = blockp->hierPrefix();
|
||||
const string argsFilename = blockp->commandArgsFilename(false);
|
||||
of.puts(blockp->hierGeneratedFilenames(true));
|
||||
of.puts(": $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
|
||||
of.puts(V3Os::filenameNonDir(argsFilename) + " ");
|
||||
const V3HierBlock::HierBlockSet& children = blockp->children();
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
of.puts((*child)->hierWrapperFilename(true) + " ");
|
||||
for (const V3GraphEdge& edge : blockp->outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
of.puts(dependencyp->hierWrapperFilename(true) + " ");
|
||||
}
|
||||
of.puts("\n");
|
||||
emitLaunchVerilator(of, argsFilename);
|
||||
|
|
@ -897,9 +898,9 @@ class EmitMkHierVerilation final {
|
|||
of.puts(": ");
|
||||
of.puts(blockp->hierMkFilename(true));
|
||||
of.puts(" ");
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
of.puts((*child)->hierLibFilename(true));
|
||||
for (const V3GraphEdge& edge : blockp->outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
of.puts(dependencyp->hierLibFilename(true));
|
||||
of.puts(" ");
|
||||
}
|
||||
of.puts("\n\t$(MAKE) -f " + blockp->hierMkFilename(false) + " -C " + prefix);
|
||||
|
|
@ -910,8 +911,8 @@ class EmitMkHierVerilation final {
|
|||
}
|
||||
|
||||
public:
|
||||
explicit EmitMkHierVerilation(const V3HierBlockPlan* planp)
|
||||
: m_planp{planp}
|
||||
explicit EmitMkHierVerilation(const V3HierGraph* graphp)
|
||||
: m_graphp{graphp}
|
||||
, m_makefile{v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_hier.mk"} {
|
||||
V3OutMkFile of{m_makefile};
|
||||
emit(of);
|
||||
|
|
@ -926,7 +927,7 @@ void V3EmitMk::emitmk() {
|
|||
const EmitMk emitter;
|
||||
}
|
||||
|
||||
void V3EmitMk::emitHierVerilation(const V3HierBlockPlan* planp) {
|
||||
void V3EmitMk::emitHierVerilation(const V3HierGraph* graphp) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
EmitMkHierVerilation{planp};
|
||||
EmitMkHierVerilation{graphp};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
class V3HierBlockPlan;
|
||||
class V3HierGraph;
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ public:
|
|||
static const size_t PARALLEL_FILE_CNT_THRESHOLD = 128;
|
||||
|
||||
static void emitmk() VL_MT_DISABLED;
|
||||
static void emitHierVerilation(const V3HierBlockPlan* planp) VL_MT_DISABLED;
|
||||
static void emitHierVerilation(const V3HierGraph* planp) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -111,64 +111,69 @@ class V3EmitMkJsonEmitter final {
|
|||
.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();
|
||||
|
||||
if (const V3HierGraph* const graphp = v3Global.hierGraphp()) {
|
||||
of.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> childDeps;
|
||||
// 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<V3HierBlock>();
|
||||
std::vector<std::string> deps;
|
||||
std::vector<std::string> sources;
|
||||
|
||||
for (const V3HierBlock* const childp : children) {
|
||||
childDeps.emplace_back(childp->hierPrefix());
|
||||
sources.emplace_back(makeDir + "/" + childp->hierWrapperFilename(true));
|
||||
for (const V3GraphEdge& edge : hblockp->outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
deps.emplace_back(dependencyp->hierPrefix());
|
||||
sources.emplace_back(makeDir + "/" + dependencyp->hierWrapperFilename(true));
|
||||
}
|
||||
|
||||
const string vFile = hblockp->vFileIfNecessary();
|
||||
const std::string vFile = hblockp->vFileIfNecessary();
|
||||
if (!vFile.empty()) sources.emplace_back(vFile);
|
||||
|
||||
for (const auto& i : v3Global.opt.vFiles())
|
||||
sources.emplace_back(
|
||||
V3Os::filenameSlashPath(V3Os::filenameRealPath(i.filename())));
|
||||
|
||||
std::vector<std::string> cflags;
|
||||
cflags.emplace_back("-fPIC");
|
||||
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", childDeps)
|
||||
.putList("deps", deps)
|
||||
.put("directory", makeDir + "/" + hblockp->hierPrefix())
|
||||
.putList("sources", sources)
|
||||
.putList("cflags", cflags)
|
||||
.putList("cflags", {"-fPIC"})
|
||||
.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));
|
||||
// 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<std::string> sources;
|
||||
for (const V3GraphVertex& vtx : graphp->vertices()) {
|
||||
const V3HierBlock* const blockp = vtx.as<V3HierBlock>();
|
||||
sources.emplace_back(makeDir + "/" + blockp->hierWrapperFilename(true));
|
||||
}
|
||||
|
||||
for (const auto& itr : v3Global.opt.vFiles())
|
||||
sources.emplace_back(
|
||||
V3Os::filenameSlashPath(V3Os::filenameRealPath(itr.filename())));
|
||||
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(
|
||||
planp->topCommandArgsFilename(true))))
|
||||
.end()
|
||||
.end();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -339,11 +339,10 @@ public:
|
|||
V3OutJsonFile& put(bool value) { return putNamed("", value ? "true" : "false", false); }
|
||||
V3OutJsonFile& put(int value) { return putNamed("", std::to_string(value), false); }
|
||||
|
||||
template <typename T>
|
||||
V3OutJsonFile& putList(const std::string& name, const T& list) {
|
||||
V3OutJsonFile& putList(const std::string& name, const std::vector<std::string>& list) {
|
||||
if (list.empty()) return *this;
|
||||
begin(name, '[');
|
||||
for (auto it = list.begin(); it != list.end(); ++it) put(*it);
|
||||
for (const std::string& str : list) put(str);
|
||||
return end();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void V3Global::boot() {
|
|||
|
||||
void V3Global::shutdown() {
|
||||
V3PreShell::shutdown();
|
||||
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
|
||||
VL_DO_CLEAR(delete m_hierGraphp, m_hierGraphp = nullptr); // delete nullptr is safe
|
||||
VL_DO_CLEAR(delete m_threadPoolp, m_threadPoolp = nullptr); // delete nullptr is safe
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include <unordered_set>
|
||||
|
||||
class AstNetlist;
|
||||
class V3HierBlockPlan;
|
||||
class V3HierGraph;
|
||||
class V3ThreadPool;
|
||||
|
||||
//======================================================================
|
||||
|
|
@ -97,12 +97,12 @@ constexpr bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
|
|||
|
||||
class V3Global final {
|
||||
// Globals
|
||||
AstNetlist* m_rootp = nullptr; // Root of entire netlist,
|
||||
// created by makeInitNetlist(} so static constructors run first
|
||||
V3HierBlockPlan* m_hierPlanp = nullptr; // Hierarchical Verilation plan,
|
||||
// nullptr unless hier_block, set via hierPlanp(V3HierBlockPlan*}
|
||||
V3ThreadPool* m_threadPoolp = nullptr; // Thread Pool,
|
||||
// nullptr unless 'verilatedJobs' is known, set via threadPoolp(V3ThreadPool*)
|
||||
// Root of entire netlist, created by makeInitNetlist(} so static constructors run first
|
||||
AstNetlist* m_rootp = nullptr;
|
||||
// Hierarchical block graph (plan) iff hierarchical verilation is performed
|
||||
V3HierGraph* m_hierGraphp = nullptr;
|
||||
// Thread Pool, nullptr unless 'verilatedJobs' is known, set via threadPoolp(V3ThreadPool*)
|
||||
V3ThreadPool* m_threadPoolp = nullptr;
|
||||
VWidthMinUsage m_widthMinUsage
|
||||
= VWidthMinUsage::LINT_WIDTH; // What AstNode::widthMin() is used for
|
||||
|
||||
|
|
@ -199,11 +199,8 @@ public:
|
|||
void setHasForceableSignals() { m_hasForceableSignals = true; }
|
||||
bool hasSCTextSections() const VL_MT_SAFE { return m_hasSCTextSections; }
|
||||
void setHasSCTextSections() { m_hasSCTextSections = true; }
|
||||
V3HierBlockPlan* hierPlanp() const { return m_hierPlanp; }
|
||||
void hierPlanp(V3HierBlockPlan* plan) {
|
||||
UASSERT(!m_hierPlanp, "call once");
|
||||
m_hierPlanp = plan;
|
||||
}
|
||||
V3HierGraph* hierGraphp() const { return m_hierGraphp; }
|
||||
void hierGraphp(V3HierGraph* graphp) { m_hierGraphp = graphp; }
|
||||
bool useParallelBuild() const { return m_useParallelBuild; }
|
||||
void useParallelBuild(bool flag) { m_useParallelBuild = flag; }
|
||||
bool useRandomizeMethods() const { return m_useRandomizeMethods; }
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of
|
|||
|
||||
//######################################################################
|
||||
|
||||
V3HierBlock::StrGParams V3HierBlock::stringifyParams(const V3HierBlockParams::GParams& gparams,
|
||||
V3HierBlock::StrGParams V3HierBlock::stringifyParams(const std::vector<AstVar*>& gparams,
|
||||
bool forGOption) {
|
||||
StrGParams strParams;
|
||||
for (const AstVar* const gparam : gparams) {
|
||||
|
|
@ -171,18 +171,19 @@ VStringList V3HierBlock::commandArgs(bool forMkJson) const {
|
|||
opts.push_back(" --protect-key " + v3Global.opt.protectKeyDefaulted());
|
||||
opts.push_back(" --hierarchical-child " + cvtToStr(v3Global.opt.threads()));
|
||||
|
||||
const StrGParams gparamsStr = stringifyParams(params().gparams(), true);
|
||||
const StrGParams gparamsStr = stringifyParams(m_params, true);
|
||||
for (const StrGParam& param : gparamsStr) {
|
||||
const string name = param.first;
|
||||
const string value = param.second;
|
||||
opts.push_back("-G" + name + "=" + value + "");
|
||||
}
|
||||
if (!params().gTypeParams().empty())
|
||||
if (!m_typeParams.empty()) {
|
||||
opts.push_back(" --hierarchical-params-file " + typeParametersFilename());
|
||||
}
|
||||
|
||||
const int blockThreads = V3Control::getHierWorkers(m_modp->origName());
|
||||
if (blockThreads > 1) {
|
||||
if (hasParent()) {
|
||||
if (!inEmpty()) {
|
||||
V3Control::getHierWorkersFileLine(m_modp->origName())
|
||||
->v3warn(E_UNSUPPORTED, "Specifying workers for nested hierarchical blocks");
|
||||
} else {
|
||||
|
|
@ -202,14 +203,13 @@ VStringList V3HierBlock::commandArgs(bool forMkJson) const {
|
|||
|
||||
VStringList V3HierBlock::hierBlockArgs() const {
|
||||
VStringList opts;
|
||||
const StrGParams gparamsStr = stringifyParams(params().gparams(), false);
|
||||
const StrGParams gparamsStr = stringifyParams(m_params, false);
|
||||
opts.push_back("--hierarchical-block ");
|
||||
string s = modp()->origName(); // origName
|
||||
s += "," + modp()->name(); // mangledName
|
||||
for (StrGParams::const_iterator paramIt = gparamsStr.begin(); paramIt != gparamsStr.end();
|
||||
++paramIt) {
|
||||
s += "," + paramIt->first;
|
||||
s += "," + paramIt->second;
|
||||
for (const StrGParam& pair : gparamsStr) {
|
||||
s += "," + pair.first;
|
||||
s += "," + pair.second;
|
||||
}
|
||||
opts.back() += s;
|
||||
return opts;
|
||||
|
|
@ -254,8 +254,9 @@ void V3HierBlock::writeCommandArgsFile(bool forMkJson) const {
|
|||
*of << "--cc\n";
|
||||
|
||||
if (!forMkJson) {
|
||||
for (const V3HierBlock* const hierblockp : m_children) {
|
||||
*of << v3Global.opt.makeDir() << "/" << hierblockp->hierWrapperFilename(true) << "\n";
|
||||
for (const V3GraphEdge& edge : outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
*of << v3Global.opt.makeDir() << "/" << dependencyp->hierWrapperFilename(true) << "\n";
|
||||
}
|
||||
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
|
||||
}
|
||||
|
|
@ -263,8 +264,9 @@ void V3HierBlock::writeCommandArgsFile(bool forMkJson) const {
|
|||
const VStringList& commandOpts = commandArgs(false);
|
||||
for (const string& opt : commandOpts) *of << opt << "\n";
|
||||
*of << hierBlockArgs().front() << "\n";
|
||||
for (const V3HierBlock* const hierblockp : m_children) {
|
||||
*of << hierblockp->hierBlockArgs().front() << "\n";
|
||||
for (const V3GraphEdge& edge : outEdges()) {
|
||||
const V3HierBlock* const dependencyp = edge.top()->as<V3HierBlock>();
|
||||
*of << dependencyp->hierBlockArgs().front() << "\n";
|
||||
}
|
||||
*of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
|
||||
}
|
||||
|
|
@ -278,13 +280,13 @@ string V3HierBlock::typeParametersFilename() const {
|
|||
}
|
||||
|
||||
void V3HierBlock::writeParametersFile() const {
|
||||
if (m_params.gTypeParams().empty()) return;
|
||||
if (m_typeParams.empty()) return;
|
||||
|
||||
VHashSha256 hash{"type params"};
|
||||
const string moduleName = "Vhsh" + hash.digestSymbol();
|
||||
const std::unique_ptr<std::ofstream> of{V3File::new_ofstream(typeParametersFilename())};
|
||||
*of << "module " << moduleName << ";\n";
|
||||
for (AstParamTypeDType* const gparam : m_params.gTypeParams()) {
|
||||
for (AstParamTypeDType* const gparam : m_typeParams) {
|
||||
AstTypedef* tdefp
|
||||
= new AstTypedef{new FileLine{FileLine::builtInFilename()}, gparam->name(), nullptr,
|
||||
VFlagChildDType{}, gparam->skipRefp()->cloneTreePure(true)};
|
||||
|
|
@ -297,176 +299,113 @@ void V3HierBlock::writeParametersFile() const {
|
|||
}
|
||||
|
||||
//######################################################################
|
||||
// Collect how hierarchical blocks are used
|
||||
// Construct graph of hierarchical blocks
|
||||
class HierBlockUsageCollectVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. Processed
|
||||
// AstNode::user1() -> bool. Already visited
|
||||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
using ModuleSet = std::unordered_set<const AstModule*>;
|
||||
V3HierBlockPlan* const m_planp;
|
||||
V3HierGraph* const m_graphp = new V3HierGraph{}; // The graph of hierarchical blocks
|
||||
// Map from hier blocks to the corresponding V3HierBlock graph vertex
|
||||
std::unordered_map<const AstModule*, V3HierBlock*> m_mod2vtx;
|
||||
AstModule* m_modp = nullptr; // The current module
|
||||
AstModule* m_hierBlockp = nullptr; // The nearest parent module that is a hierarchical block
|
||||
ModuleSet m_referred; // Modules that have hier_block pragma
|
||||
V3HierBlockParams m_params;
|
||||
std::vector<AstVar*> m_params; // Overridden value parameters of current module
|
||||
std::vector<AstParamTypeDType*> m_typeParams; // Type parameters of current module
|
||||
// Hierarchical blocks instanciated (possibly indirectly) by current hierarchical block
|
||||
std::vector<V3HierBlock*> m_childrenp;
|
||||
|
||||
// VISITORSs
|
||||
void visit(AstNodeModule*) override {} // Ignore all non AstModule
|
||||
void visit(AstModule* nodep) override {
|
||||
// Don't visit twice
|
||||
// Visit each module once
|
||||
if (nodep->user1SetOnce()) return;
|
||||
UINFO(5, "Checking " << nodep->prettyNameQ() << " from "
|
||||
<< (m_hierBlockp ? m_hierBlockp->prettyNameQ() : "null"s));
|
||||
|
||||
UINFO(5, "Visiting " << nodep->prettyNameQ());
|
||||
VL_RESTORER(m_modp);
|
||||
AstModule* const prevHierBlockp = m_hierBlockp;
|
||||
ModuleSet prevReferred;
|
||||
V3HierBlockParams previousParams;
|
||||
m_modp = nodep;
|
||||
if (nodep->hierBlock()) {
|
||||
m_hierBlockp = nodep;
|
||||
prevReferred.swap(m_referred);
|
||||
}
|
||||
previousParams.swap(m_params);
|
||||
|
||||
// If not a hierarchical block, just iterate and return
|
||||
if (!nodep->hierBlock()) {
|
||||
iterateChildrenConst(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a hierarchical block, gather parts
|
||||
VL_RESTORER(m_params);
|
||||
VL_RESTORER(m_typeParams);
|
||||
VL_RESTORER(m_childrenp);
|
||||
m_params.clear();
|
||||
m_typeParams.clear();
|
||||
m_childrenp.clear();
|
||||
iterateChildrenConst(nodep);
|
||||
|
||||
if (nodep->hierBlock()) {
|
||||
m_planp->add(nodep, m_params);
|
||||
for (const AstModule* modp : m_referred) m_planp->registerUsage(nodep, modp);
|
||||
m_hierBlockp = prevHierBlockp;
|
||||
m_referred = prevReferred;
|
||||
}
|
||||
m_params.swap(previousParams);
|
||||
// Create the graph vertex for this hier block
|
||||
V3HierBlock* const blockp = new V3HierBlock{m_graphp, nodep, m_params, m_typeParams};
|
||||
// Record it
|
||||
m_mod2vtx[nodep] = blockp;
|
||||
// Add an edge to each child block
|
||||
for (V3HierBlock* const childp : m_childrenp) new V3GraphEdge{m_graphp, blockp, childp, 1};
|
||||
}
|
||||
void visit(AstCell* nodep) override {
|
||||
// Visit used module here to know that the module is hier_block or not.
|
||||
// This visitor behaves almost depth first search
|
||||
if (AstModule* const modp = VN_CAST(nodep->modp(), Module)) {
|
||||
iterateConst(modp);
|
||||
m_referred.insert(modp);
|
||||
}
|
||||
// Nothing to do for interface because hierarchical block does not exist
|
||||
// beyond interface.
|
||||
// Nothing to do for non AstModules because hierarchical block cannot exist under them.
|
||||
AstModule* const modp = VN_CAST(nodep->modp(), Module);
|
||||
if (!modp) return;
|
||||
// Depth-first traversal of module hierechy
|
||||
iterateConst(modp);
|
||||
// If this is an instance of a hierarchical block, add to child array to link parent
|
||||
if (modp->hierBlock()) m_childrenp.emplace_back(m_mod2vtx.at(modp));
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
if (m_modp && m_modp->hierBlock() && nodep->isIfaceRef() && !nodep->isIfaceParent()) {
|
||||
nodep->v3error("Modport cannot be used at the hierarchical block boundary");
|
||||
}
|
||||
if (nodep->isGParam() && nodep->overriddenParam()) m_params.add(nodep);
|
||||
// Record overridden value parameter
|
||||
if (nodep->isGParam() && nodep->overriddenParam()) {
|
||||
UASSERT_OBJ(m_modp, nodep, "Value parameter not under module");
|
||||
m_params.push_back(nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstParamTypeDType* nodep) override {
|
||||
// Record type parameter
|
||||
UASSERT_OBJ(m_modp, nodep, "Type parameter not under module");
|
||||
m_typeParams.push_back(nodep);
|
||||
}
|
||||
|
||||
void visit(AstParamTypeDType* nodep) override { m_params.add(nodep); }
|
||||
|
||||
void visit(AstNodeStmt*) override {} // Accelerate
|
||||
void visit(AstNodeExpr*) override {} // Accelerate
|
||||
void visit(AstConstPool*) override {} // Accelerate
|
||||
void visit(AstTypeTable*) override {} // Accelerate
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
// CONSTRUCTOR
|
||||
HierBlockUsageCollectVisitor(AstNetlist* netlistp) {
|
||||
iterateChildrenConst(netlistp);
|
||||
if (dumpGraphLevel() >= 3) m_graphp->dumpDotFilePrefixed("hierblocks_initial");
|
||||
// Simplify dependencies
|
||||
m_graphp->removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
|
||||
// Topologically sorder the graph
|
||||
m_graphp->order(); // This is a bit heavy weight, but does produce a topological ordering
|
||||
if (dumpGraphLevel() >= 3) m_graphp->dumpDotFilePrefixed("hierblocks");
|
||||
}
|
||||
|
||||
public:
|
||||
HierBlockUsageCollectVisitor(V3HierBlockPlan* planp, AstNetlist* netlist)
|
||||
: m_planp{planp} {
|
||||
iterateChildrenConst(netlist);
|
||||
static V3HierGraph* apply(AstNetlist* netlistp) {
|
||||
return HierBlockUsageCollectVisitor{netlistp}.m_graphp;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
void V3HierGraph::writeCommandArgsFiles(bool forMkJson) const {
|
||||
|
||||
void V3HierBlockPlan::add(const AstNodeModule* modp, const V3HierBlockParams& params) {
|
||||
const bool newEntry = m_blocks
|
||||
.emplace(std::piecewise_construct, std::forward_as_tuple(modp),
|
||||
std::forward_as_tuple(modp, params))
|
||||
.second;
|
||||
if (newEntry) {
|
||||
UINFO(3, "Add " << modp->prettyNameQ() << " with " << params.gparams().size()
|
||||
<< " parameters and " << params.gTypeParams().size()
|
||||
<< " type parameters");
|
||||
}
|
||||
}
|
||||
|
||||
void V3HierBlockPlan::registerUsage(const AstNodeModule* parentp, const AstNodeModule* childp) {
|
||||
const iterator parent = m_blocks.find(parentp);
|
||||
UASSERT_OBJ(parent != m_blocks.end(), parentp, "must be added");
|
||||
const iterator child = m_blocks.find(childp);
|
||||
if (child != m_blocks.end()) {
|
||||
UINFO(3, "Found usage relation " << parentp->prettyNameQ() << " uses "
|
||||
<< childp->prettyNameQ());
|
||||
parent->second.addChild(&child->second);
|
||||
child->second.addParent(&parent->second);
|
||||
}
|
||||
}
|
||||
|
||||
void V3HierBlockPlan::createPlan(AstNetlist* nodep) {
|
||||
// When processing a hierarchical block, no need to create a plan anymore.
|
||||
if (v3Global.opt.hierChild()) return;
|
||||
|
||||
AstNodeModule* const modp = nodep->topModulep();
|
||||
if (modp->hierBlock()) {
|
||||
modp->v3warn(HIERBLOCK,
|
||||
"Top module illegally marked hierarchical block, ignoring marking\n"
|
||||
+ modp->warnMore()
|
||||
+ "... Suggest remove verilator hier_block on this module");
|
||||
modp->hierBlock(false);
|
||||
}
|
||||
|
||||
std::unique_ptr<V3HierBlockPlan> planp(new V3HierBlockPlan);
|
||||
{ HierBlockUsageCollectVisitor{planp.get(), nodep}; }
|
||||
|
||||
V3Stats::addStat("HierBlock, Hierarchical blocks", planp->m_blocks.size());
|
||||
|
||||
// No hierarchical block is found, nothing to do.
|
||||
if (planp->empty()) return;
|
||||
|
||||
v3Global.hierPlanp(planp.release());
|
||||
}
|
||||
|
||||
V3HierBlockPlan::HierVector V3HierBlockPlan::hierBlocksSorted() const {
|
||||
using ChildrenMap
|
||||
= std::unordered_map<const V3HierBlock*, std::unordered_set<const V3HierBlock*>>;
|
||||
ChildrenMap childrenOfHierBlock;
|
||||
|
||||
HierVector sorted;
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
if (!it->second.hasChild()) { // No children, already leaf
|
||||
sorted.push_back(&it->second);
|
||||
} else {
|
||||
ChildrenMap::value_type::second_type& childrenSet
|
||||
= childrenOfHierBlock[&it->second]; // insert
|
||||
const V3HierBlock::HierBlockSet& c = it->second.children();
|
||||
childrenSet.insert(c.begin(), c.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Use index instead of iterator because new elements will be added in this loop
|
||||
for (size_t i = 0; i < sorted.size(); ++i) {
|
||||
// This hblockp is already leaf.
|
||||
const V3HierBlock* hblockp = sorted[i];
|
||||
const V3HierBlock::HierBlockSet& p = hblockp->parents();
|
||||
for (V3HierBlock::HierBlockSet::const_iterator it = p.begin(); it != p.end(); ++it) {
|
||||
// Delete hblockp from parents. If a parent does not have a child anymore, then it is
|
||||
// a leaf too.
|
||||
const auto parentIt = childrenOfHierBlock.find(*it);
|
||||
UASSERT_OBJ(parentIt != childrenOfHierBlock.end(), (*it)->modp(), "must be included");
|
||||
const V3HierBlock::HierBlockSet::size_type erased = parentIt->second.erase(hblockp);
|
||||
UASSERT_OBJ(erased == 1, hblockp->modp(),
|
||||
" must be a child of " << parentIt->first->modp());
|
||||
if (parentIt->second.empty()) { // Now parentIt is leaf
|
||||
sorted.push_back(parentIt->first);
|
||||
childrenOfHierBlock.erase(parentIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
void V3HierBlockPlan::writeCommandArgsFiles(bool forMkJson) const {
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
it->second.writeCommandArgsFile(forMkJson);
|
||||
for (const V3GraphVertex& vtx : vertices()) {
|
||||
vtx.as<V3HierBlock>()->writeCommandArgsFile(forMkJson);
|
||||
}
|
||||
// For the top module
|
||||
const std::unique_ptr<std::ofstream> of{
|
||||
V3File::new_ofstream(topCommandArgsFilename(forMkJson))};
|
||||
if (!forMkJson) {
|
||||
// Load wrappers first not to be overwritten by the original HDL
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
*of << it->second.hierWrapperFilename(true) << "\n";
|
||||
for (const V3GraphVertex& vtx : vertices()) {
|
||||
*of << vtx.as<V3HierBlock>()->hierWrapperFilename(true) << "\n";
|
||||
}
|
||||
}
|
||||
V3HierWriteCommonInputs(nullptr, of.get(), forMkJson);
|
||||
|
|
@ -478,8 +417,8 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forMkJson) const {
|
|||
*of << "-Mdir " << v3Global.opt.makeDir() << "\n";
|
||||
*of << "--mod-prefix " << v3Global.opt.modPrefix() << "\n";
|
||||
}
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
*of << it->second.hierBlockArgs().front() << "\n";
|
||||
for (const V3GraphVertex& vtx : vertices()) {
|
||||
*of << vtx.as<V3HierBlock>()->hierBlockArgs().front() << "\n";
|
||||
}
|
||||
|
||||
if (!v3Global.opt.libCreate().empty()) {
|
||||
|
|
@ -493,10 +432,34 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forMkJson) const {
|
|||
*of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
|
||||
}
|
||||
|
||||
string V3HierBlockPlan::topCommandArgsFilename(bool forMkJson) {
|
||||
string V3HierGraph::topCommandArgsFilename(bool forMkJson) {
|
||||
return V3HierCommandArgsFilename(v3Global.opt.prefix(), forMkJson);
|
||||
}
|
||||
|
||||
void V3HierBlockPlan::writeParametersFiles() const {
|
||||
for (const auto& block : *this) block.second.writeParametersFile();
|
||||
void V3HierGraph::writeParametersFiles() const {
|
||||
for (const V3GraphVertex& vtx : vertices()) { vtx.as<V3HierBlock>()->writeParametersFile(); }
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
void V3Hierarchical::createGraph(AstNetlist* netlistp) {
|
||||
UASSERT(!v3Global.hierGraphp(), "Should only be called once");
|
||||
|
||||
AstNodeModule* const modp = netlistp->topModulep();
|
||||
if (modp->hierBlock()) {
|
||||
modp->v3warn(HIERBLOCK, "Top module marked as hierarchical block, ignoring\n"
|
||||
+ modp->warnMore()
|
||||
+ "... Suggest remove verilator hier_block on this module");
|
||||
modp->hierBlock(false);
|
||||
}
|
||||
|
||||
V3HierGraph* const graphp = HierBlockUsageCollectVisitor::apply(netlistp);
|
||||
V3Stats::addStat("HierBlock, Hierarchical blocks", graphp->vertices().size());
|
||||
// No hierarchical block is found, nothing to do.
|
||||
if (graphp->empty()) {
|
||||
VL_DO_DANGLING(delete graphp, graphp);
|
||||
return;
|
||||
}
|
||||
// Hold on to the graph
|
||||
v3Global.hierGraphp(graphp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Options.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -36,68 +37,51 @@ class AstVar;
|
|||
|
||||
//######################################################################
|
||||
|
||||
class V3HierBlockParams final {
|
||||
class V3HierGraph final : public V3Graph {
|
||||
public:
|
||||
using GParams = std::vector<AstVar*>;
|
||||
using GTypeParams = std::vector<AstParamTypeDType*>;
|
||||
V3HierGraph() = default;
|
||||
~V3HierGraph() = default;
|
||||
VL_UNCOPYABLE(V3HierGraph);
|
||||
VL_UNMOVABLE(V3HierGraph);
|
||||
|
||||
private:
|
||||
GParams m_params;
|
||||
GTypeParams m_typeParams;
|
||||
|
||||
public:
|
||||
void add(AstVar* param) { m_params.push_back(param); }
|
||||
void add(AstParamTypeDType* param) { m_typeParams.push_back(param); }
|
||||
|
||||
const GParams& gparams() const { return m_params; };
|
||||
const GTypeParams& gTypeParams() const { return m_typeParams; };
|
||||
|
||||
void swap(V3HierBlockParams& other) {
|
||||
m_params.swap(other.m_params);
|
||||
m_typeParams.swap(other.m_typeParams);
|
||||
}
|
||||
// Write command line arguments to .f files for child Verilation run
|
||||
void writeCommandArgsFiles(bool forMkJson) const VL_MT_DISABLED;
|
||||
void writeParametersFiles() const VL_MT_DISABLED;
|
||||
static string topCommandArgsFilename(bool forMkJson) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3HierBlock final {
|
||||
public:
|
||||
using HierBlockSet = std::unordered_set<V3HierBlock*>;
|
||||
class V3HierBlock final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(V3HierBlock, V3GraphVertex)
|
||||
|
||||
private:
|
||||
// TYPES
|
||||
// Parameter name, stringified value
|
||||
using StrGParam = std::pair<string, string>;
|
||||
using StrGParams = std::vector<StrGParam>;
|
||||
|
||||
// MEMBERS
|
||||
const AstNodeModule* const m_modp; // Hierarchical block module
|
||||
// Hierarchical blocks that directly or indirectly instantiate this block
|
||||
HierBlockSet m_parents;
|
||||
// Hierarchical blocks that this block directly or indirectly instantiates
|
||||
HierBlockSet m_children;
|
||||
// Parameters that are overridden by #(.param(value)) syntax.
|
||||
const V3HierBlockParams m_params;
|
||||
const AstModule* const m_modp; // Hierarchical block module
|
||||
// Value parameters that are overridden by #(.param(value)) syntax.
|
||||
const std::vector<AstVar*> m_params;
|
||||
// Types parameters that are overridden by #(.param(value)) syntax.
|
||||
const std::vector<AstParamTypeDType*> m_typeParams;
|
||||
|
||||
// METHODS
|
||||
VL_UNCOPYABLE(V3HierBlock);
|
||||
VL_UNMOVABLE(V3HierBlock);
|
||||
static StrGParams stringifyParams(const V3HierBlockParams::GParams& params,
|
||||
static StrGParams stringifyParams(const std::vector<AstVar*>& params,
|
||||
bool forGOption) VL_MT_DISABLED;
|
||||
|
||||
public:
|
||||
V3HierBlock(const AstNodeModule* modp, const V3HierBlockParams& params)
|
||||
: m_modp{modp}
|
||||
, m_params{params} {}
|
||||
|
||||
// CONSTRUCTORs
|
||||
V3HierBlock(V3HierGraph* graphp, const AstModule* modp, const std::vector<AstVar*>& params,
|
||||
const std::vector<AstParamTypeDType*>& typeParams)
|
||||
: V3GraphVertex{graphp}
|
||||
, m_modp{modp}
|
||||
, m_params{params}
|
||||
, m_typeParams{typeParams} {}
|
||||
~V3HierBlock() VL_MT_DISABLED = default;
|
||||
VL_UNCOPYABLE(V3HierBlock);
|
||||
VL_UNMOVABLE(V3HierBlock);
|
||||
|
||||
void addParent(V3HierBlock* parentp) { m_parents.insert(parentp); }
|
||||
bool hasParent() const { return !m_parents.empty(); }
|
||||
void addChild(V3HierBlock* childp) { m_children.insert(childp); }
|
||||
bool hasChild() const { return !m_children.empty(); }
|
||||
const HierBlockSet& parents() const { return m_parents; }
|
||||
const HierBlockSet& children() const { return m_children; }
|
||||
const V3HierBlockParams& params() const { return m_params; }
|
||||
const AstNodeModule* modp() const { return m_modp; }
|
||||
const AstModule* modp() const { return m_modp; }
|
||||
|
||||
// For emitting Makefile and build definition JSON
|
||||
VStringList commandArgs(bool forMkJson) const VL_MT_DISABLED;
|
||||
|
|
@ -116,41 +100,18 @@ public:
|
|||
void writeParametersFile() const VL_MT_DISABLED;
|
||||
string commandArgsFilename(bool forMkJson) const VL_MT_DISABLED;
|
||||
string typeParametersFilename() const VL_MT_DISABLED;
|
||||
|
||||
// For Graphviz dumps only
|
||||
std::string name() const override { return m_modp->prettyNameQ(); }
|
||||
std::string dotShape() const override { return "box"; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Pass to create hierarcical block graph
|
||||
|
||||
// Holds relationship between AstNodeModule and V3HierBlock
|
||||
class V3HierBlockPlan final {
|
||||
// TODO: this map is non-deterministic
|
||||
using HierMap = std::unordered_map<const AstNodeModule*, V3HierBlock>;
|
||||
HierMap m_blocks;
|
||||
|
||||
V3HierBlockPlan() = default;
|
||||
VL_UNCOPYABLE(V3HierBlockPlan);
|
||||
|
||||
class V3Hierarchical final {
|
||||
public:
|
||||
using iterator = HierMap::iterator;
|
||||
using const_iterator = HierMap::const_iterator;
|
||||
using HierVector = std::vector<const V3HierBlock*>;
|
||||
|
||||
void add(const AstNodeModule* modp, const V3HierBlockParams& params) VL_MT_DISABLED;
|
||||
void registerUsage(const AstNodeModule* parentp, const AstNodeModule* childp) VL_MT_DISABLED;
|
||||
|
||||
const_iterator begin() const { return m_blocks.begin(); }
|
||||
const_iterator end() const { return m_blocks.end(); }
|
||||
bool empty() const { return m_blocks.empty(); }
|
||||
|
||||
// Returns all hierarchical blocks that sorted in leaf-first order.
|
||||
// Latter block refers only already appeared hierarchical blocks.
|
||||
HierVector hierBlocksSorted() const VL_MT_DISABLED;
|
||||
|
||||
// Write command line arguments to .f files for child Verilation run
|
||||
void writeCommandArgsFiles(bool forMkJson) const VL_MT_DISABLED;
|
||||
void writeParametersFiles() const VL_MT_DISABLED;
|
||||
static string topCommandArgsFilename(bool forMkJson) VL_MT_DISABLED;
|
||||
|
||||
static void createPlan(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static void createGraph(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
|
|
|||
|
|
@ -193,11 +193,11 @@ static void process() {
|
|||
|
||||
// Create a hierarchical Verilation plan
|
||||
if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()
|
||||
&& v3Global.opt.hierarchical()) {
|
||||
V3HierBlockPlan::createPlan(v3Global.rootp());
|
||||
&& v3Global.opt.hierarchical() && !v3Global.opt.hierChild()) {
|
||||
V3Hierarchical::createGraph(v3Global.rootp());
|
||||
// If a plan is created, further analysis is not necessary.
|
||||
// The actual Verilation will be done based on this plan.
|
||||
if (v3Global.hierPlanp()) {
|
||||
if (v3Global.hierGraphp()) {
|
||||
reportStatsIfEnabled();
|
||||
return;
|
||||
}
|
||||
|
|
@ -744,23 +744,24 @@ static bool verilate(const string& argString) {
|
|||
|
||||
V3Error::abortIfWarnings();
|
||||
|
||||
if (v3Global.hierPlanp()) { // This run is for just write a makefile
|
||||
if (V3HierGraph* const hierGraphp
|
||||
= v3Global.hierGraphp()) { // This run is for just write a makefile
|
||||
UASSERT(v3Global.opt.hierarchical(), "hierarchical must be set");
|
||||
UASSERT(!v3Global.opt.hierChild(), "This must not be a hierarchical-child run");
|
||||
UASSERT(v3Global.opt.hierBlocks().empty(), "hierarchical-block must not be set");
|
||||
if (v3Global.opt.gmake()) {
|
||||
v3Global.hierPlanp()->writeCommandArgsFiles(false);
|
||||
V3EmitMk::emitHierVerilation(v3Global.hierPlanp());
|
||||
hierGraphp->writeCommandArgsFiles(false);
|
||||
V3EmitMk::emitHierVerilation(hierGraphp);
|
||||
}
|
||||
if (v3Global.opt.cmake()) {
|
||||
v3Global.hierPlanp()->writeCommandArgsFiles(true);
|
||||
hierGraphp->writeCommandArgsFiles(true);
|
||||
V3EmitCMake::emit();
|
||||
}
|
||||
if (v3Global.opt.makeJson()) {
|
||||
v3Global.hierPlanp()->writeCommandArgsFiles(true);
|
||||
hierGraphp->writeCommandArgsFiles(true);
|
||||
V3EmitMkJson::emit();
|
||||
}
|
||||
v3Global.hierPlanp()->writeParametersFiles();
|
||||
hierGraphp->writeParametersFiles();
|
||||
}
|
||||
if (v3Global.opt.makeDepend().isTrue()) {
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix();
|
||||
|
|
@ -835,7 +836,7 @@ static void execBuildJob() {
|
|||
}
|
||||
|
||||
static void execHierVerilation() {
|
||||
UASSERT(v3Global.hierPlanp(), "must be called only when plan exists");
|
||||
UASSERT(v3Global.hierGraphp(), "must be called only when plan exists");
|
||||
const string makefile = v3Global.opt.prefix() + "_hier.mk ";
|
||||
const string target = v3Global.opt.build() ? " hier_build" : " hier_verilation";
|
||||
const string cmdStr = buildMakeCmd(makefile, target);
|
||||
|
|
@ -885,7 +886,7 @@ int main(int argc, char** argv) {
|
|||
UINFO(1, "Option --no-verilate: Skip Verilation");
|
||||
}
|
||||
|
||||
if (v3Global.hierPlanp() && v3Global.opt.gmake()) {
|
||||
if (v3Global.hierGraphp() && v3Global.opt.gmake()) {
|
||||
execHierVerilation(); // execHierVerilation() takes care of --build too
|
||||
} else if (v3Global.opt.build()) {
|
||||
execBuildJob();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%Warning-HIERBLOCK: t/t_hier_block1_bad.v:16:8: Top module illegally marked hierarchical block, ignoring marking
|
||||
%Warning-HIERBLOCK: t/t_hier_block1_bad.v:16:8: Top module marked as hierarchical block, ignoring
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest remove verilator hier_block on this module
|
||||
16 | module t (
|
||||
|
|
|
|||
Loading…
Reference in New Issue