Fix linking parameterized hierarchical blocks and recursive hierarchical blocks (#4654)

This commit is contained in:
Anthony Donlon 2023-11-03 11:55:53 +00:00 committed by GitHub
parent 2733d43ea7
commit d0d39c13e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 24518 additions and 23367 deletions

View File

@ -610,7 +610,7 @@ void V3Config::applyIgnores(FileLine* filelinep) {
} }
void V3Config::applyModule(AstNodeModule* modulep) { void V3Config::applyModule(AstNodeModule* modulep) {
const string& modname = modulep->name(); const string& modname = modulep->origName();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname); V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (modp) modp->apply(modulep); if (modp) modp->apply(modulep);
} }

View File

@ -74,6 +74,7 @@ class ParameterizedHierBlocks final {
using GParamsMap = std::map<const std::string, AstVar*>; // key:parameter name value:parameter using GParamsMap = std::map<const std::string, AstVar*>; // key:parameter name value:parameter
// MEMBERS // MEMBERS
const bool m_hierSubRun; // Is in sub-run for hierarchical verilation
// key:Original module name, value:HiearchyBlockOption* // key:Original module name, value:HiearchyBlockOption*
// If a module is parameterized, the module is uniquified to overridden parameters. // If a module is parameterized, the module is uniquified to overridden parameters.
// This is why HierBlockOptsByOrigName is multimap. // This is why HierBlockOptsByOrigName is multimap.
@ -88,7 +89,8 @@ class ParameterizedHierBlocks final {
// METHODS // METHODS
public: public:
ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) { ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep)
: m_hierSubRun(!v3Global.opt.hierBlocks().empty() || v3Global.opt.hierChild()) {
for (const auto& hierOpt : hierOpts) { for (const auto& hierOpt : hierOpts) {
m_hierBlockOptsByOrigName.emplace(hierOpt.second.origName(), &hierOpt.second); m_hierBlockOptsByOrigName.emplace(hierOpt.second.origName(), &hierOpt.second);
const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params(); const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params();
@ -109,7 +111,11 @@ public:
if (hierOpts.find(modp->prettyName()) != hierOpts.end()) { if (hierOpts.find(modp->prettyName()) != hierOpts.end()) {
m_hierBlockMod.emplace(modp->name(), modp); m_hierBlockMod.emplace(modp->name(), modp);
} }
const auto defParamIt = m_modParams.find(modp->name()); // Recursive hierarchical module may change its name, so we have to match its origName.
// Collect values from recursive cloned module as parameters in the top module could be
// overridden.
const string actualModName = modp->recursiveClone() ? modp->origName() : modp->name();
const auto defParamIt = m_modParams.find(actualModName);
if (defParamIt != m_modParams.end()) { if (defParamIt != m_modParams.end()) {
// modp is the original of parameterized hierarchical block // modp is the original of parameterized hierarchical block
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
@ -120,11 +126,13 @@ public:
} }
} }
} }
bool hierSubRun() const { return m_hierSubRun; }
bool isHierBlock(const string& origName) const {
return m_hierBlockOptsByOrigName.find(origName) != m_hierBlockOptsByOrigName.end();
}
AstNodeModule* findByParams(const string& origName, AstPin* firstPinp, AstNodeModule* findByParams(const string& origName, AstPin* firstPinp,
const AstNodeModule* modp) { const AstNodeModule* modp) {
if (m_hierBlockOptsByOrigName.find(origName) == m_hierBlockOptsByOrigName.end()) { UASSERT(isHierBlock(origName), origName << " is not hierarchical block\n");
return nullptr;
}
// This module is a hierarchical block. Need to replace it by the --lib-create wrapper. // This module is a hierarchical block. Need to replace it by the --lib-create wrapper.
const std::pair<HierMapIt, HierMapIt> candidates const std::pair<HierMapIt, HierMapIt> candidates
= m_hierBlockOptsByOrigName.equal_range(origName); = m_hierBlockOptsByOrigName.equal_range(origName);
@ -510,9 +518,9 @@ class ParamProcessor final {
pair.first->second = std::move(params); pair.first->second = std::move(params);
} }
const auto paramsIt = pair.first; const auto paramsIt = pair.first;
if (paramsIt->second.empty()) return modp->name(); // modp has no parameter if (paramsIt->second.empty()) return modp->origName(); // modp has no parameter
string longname = modp->name(); string longname = modp->origName();
for (auto&& defaultValue : paramsIt->second) { for (auto&& defaultValue : paramsIt->second) {
const auto pinIt = pins.find(defaultValue.first); const auto pinIt = pins.find(defaultValue.first);
const AstConst* const constp const AstConst* const constp
@ -536,7 +544,7 @@ class ParamProcessor final {
// Hex string must be a safe suffix for any symbol // Hex string must be a safe suffix for any symbol
const string hashStr = hashStrGen.digestHex(); const string hashStr = hashStrGen.digestHex();
for (string::size_type i = 1; i < hashStr.size(); ++i) { for (string::size_type i = 1; i < hashStr.size(); ++i) {
string newName = modp->name(); string newName = modp->origName();
// Don't use '__' not to be encoded when this module is loaded later by Verilator // Don't use '__' not to be encoded when this module is loaded later by Verilator
if (newName.at(newName.size() - 1) != '_') newName += '_'; if (newName.at(newName.size() - 1) != '_') newName += '_';
newName += hashStr.substr(0, i); newName += hashStr.substr(0, i);
@ -586,8 +594,6 @@ class ParamProcessor final {
newmodp->user2(false); // We need to re-recurse this module once changed newmodp->user2(false); // We need to re-recurse this module once changed
newmodp->recursive(false); newmodp->recursive(false);
newmodp->recursiveClone(false); newmodp->recursiveClone(false);
// Only the first generation of clone holds this property
newmodp->hierBlock(srcModp->hierBlock() && !srcModp->recursiveClone());
// Recursion may need level cleanups // Recursion may need level cleanups
if (newmodp->level() <= m_modp->level()) newmodp->level(m_modp->level() + 1); if (newmodp->level() <= m_modp->level()) newmodp->level(m_modp->level() + 1);
if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) { if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) {
@ -851,7 +857,16 @@ class ParamProcessor final {
cellInterfaceCleanup(pinsp, srcModpr, longname /*ref*/, any_overrides /*ref*/, cellInterfaceCleanup(pinsp, srcModpr, longname /*ref*/, any_overrides /*ref*/,
ifaceRefRefs /*ref*/); ifaceRefRefs /*ref*/);
if (!any_overrides) { if (m_hierBlocks.hierSubRun() && m_hierBlocks.isHierBlock(srcModpr->origName())) {
AstNodeModule* const paramedModp
= m_hierBlocks.findByParams(srcModpr->origName(), paramsp, m_modp);
UASSERT_OBJ(paramedModp, nodep, "Failed to find sub-module for hierarchical block");
paramedModp->dead(false);
// We need to relink the pins to the new module
relinkPinsByName(pinsp, paramedModp);
srcModpr = paramedModp;
any_overrides = true;
} else if (!any_overrides) {
UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
// If it's the first use of the default instance, create a copy and store it in user3p. // If it's the first use of the default instance, create a copy and store it in user3p.
// user3p will also be used to check if the default instance is used. // user3p will also be used to check if the default instance is used.
@ -863,12 +878,6 @@ class ParamProcessor final {
srcModpr->user3p(classCopyp); srcModpr->user3p(classCopyp);
storeOriginalParams(classCopyp); storeOriginalParams(classCopyp);
} }
} else if (AstNodeModule* const paramedModp
= m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) {
paramedModp->dead(false);
// We need to relink the pins to the new module
relinkPinsByName(pinsp, paramedModp);
srcModpr = paramedModp;
} else { } else {
const string newname const string newname
= srcModpr->hierBlock() ? longname : moduleCalcName(srcModpr, longname); = srcModpr->hierBlock() ? longname : moduleCalcName(srcModpr, longname);

View File

@ -35,7 +35,7 @@ file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", qr/^\s+\/\/\s+timeprecision\s+(\d
file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0");
file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1");
file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2");
file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus");
ok(1); ok(1);

View File

@ -36,7 +36,7 @@ if (!$Self->have_cmake) {
file_grep($target_dir . 'Vsub0/sub0.sv', /^module\s+(\S+)\s+/, "sub0"); file_grep($target_dir . 'Vsub0/sub0.sv', /^module\s+(\S+)\s+/, "sub0");
file_grep($target_dir . 'Vsub1/sub1.sv', /^module\s+(\S+)\s+/, "sub1"); file_grep($target_dir . 'Vsub1/sub1.sv', /^module\s+(\S+)\s+/, "sub1");
file_grep($target_dir . 'Vsub2/sub2.sv', /^module\s+(\S+)\s+/, "sub2"); file_grep($target_dir . 'Vsub2/sub2.sv', /^module\s+(\S+)\s+/, "sub2");
file_grep($target_dir . 'Vt_hier_block__stats.txt', qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($target_dir . 'Vt_hier_block__stats.txt', qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{obj_dir} . '/run.log', qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{obj_dir} . '/run.log', qr/MACRO:(\S+) is defined/i, "cplusplus");
} }

View File

@ -35,7 +35,7 @@ execute(
file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0");
file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1");
file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2");
file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus");
ok(1); ok(1);

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ execute(
file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0");
file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1");
file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2");
file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus");
fst_identical($Self->trace_filename, $Self->{golden_filename}); fst_identical($Self->trace_filename, $Self->{golden_filename});

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ execute(
file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0");
file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1");
file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2");
file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus");
vcd_identical($Self->trace_filename, $Self->{golden_filename}); vcd_identical($Self->trace_filename, $Self->{golden_filename});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@ file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", qr/^\s+timeprecision\s+(\d+)ps;/m
file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0");
file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1");
file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2");
file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 13); file_grep($Self->{stats}, qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 14);
file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus");
ok(1); ok(1);

View File

@ -6,4 +6,4 @@
`verilator_config `verilator_config
hier_block -module "sub?" hier_block -module "sub?"
hier_block -module "delay" hier_block -module "delay" // matches recursive modules