parent
18dd44e970
commit
8c252952db
|
|
@ -73,6 +73,17 @@ public:
|
||||||
string name() const override VL_MT_STABLE { return "*LIBRARY*"; }
|
string name() const override VL_MT_STABLE { return "*LIBRARY*"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CellEdge final : public V3GraphEdge {
|
||||||
|
VL_RTTI_IMPL(CellEdge, V3GraphEdge)
|
||||||
|
AstCell* const m_cellp;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CellEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable, AstCell* cellp)
|
||||||
|
: V3GraphEdge{graphp, fromp, top, weight, cutable}, m_cellp{cellp} {}
|
||||||
|
AstCell* cellp() const { return m_cellp; }
|
||||||
|
string name() const override VL_MT_STABLE { return cellp() ? cvtToHex(cellp()) + ' ' + cellp()->name() : ""; }
|
||||||
|
};
|
||||||
|
|
||||||
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) {
|
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFuncp) {
|
||||||
if (const LinkCellsVertex* const vvertexp = vertexp->cast<LinkCellsVertex>()) {
|
if (const LinkCellsVertex* const vvertexp = vertexp->cast<LinkCellsVertex>()) {
|
||||||
vvertexp->modp()->v3warn(E_UNSUPPORTED,
|
vvertexp->modp()->v3warn(E_UNSUPPORTED,
|
||||||
|
|
@ -94,7 +105,7 @@ void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp, V3EdgeFuncP edgeFunc
|
||||||
// State to pass between config parsing and cell linking visitors.
|
// State to pass between config parsing and cell linking visitors.
|
||||||
struct LinkCellsState final {
|
struct LinkCellsState final {
|
||||||
// Set of possible top module names from command line and configs
|
// Set of possible top module names from command line and configs
|
||||||
std::unordered_set<std::string> m_topModuleNames;
|
std::vector<std::pair<std::string, std::string>> m_designs;
|
||||||
// Default library lists to search
|
// Default library lists to search
|
||||||
std::vector<std::string> m_liblistDefault;
|
std::vector<std::string> m_liblistDefault;
|
||||||
// Library lists for specific cells
|
// Library lists for specific cells
|
||||||
|
|
@ -102,56 +113,84 @@ struct LinkCellsState final {
|
||||||
// Use list for specific cells (libname, cellname)
|
// Use list for specific cells (libname, cellname)
|
||||||
std::unordered_map<std::string, std::vector<std::pair<std::string, std::string>>>
|
std::unordered_map<std::string, std::vector<std::pair<std::string, std::string>>>
|
||||||
m_uselistCell;
|
m_uselistCell;
|
||||||
|
// Library lists for specific insts
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> m_liblistInst;
|
||||||
|
// Use list for specific insts (libname, cellname)
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, std::string>>>
|
||||||
|
m_uselistInst;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LinkConfigsVisitor final : public VNVisitor {
|
class LinkConfigsVisitor final : public VNVisitor {
|
||||||
// STATE
|
// STATE
|
||||||
LinkCellsState& m_state; // Context for linking cells
|
LinkCellsState& m_state; // Context for linking cells
|
||||||
|
bool m_isTop = false; // Whether we're in the top-level config
|
||||||
|
bool m_isDefault = false; // Whether we're currently in a default clause
|
||||||
|
string m_cell; // Current cell being processed
|
||||||
|
string m_hierInst; // Current hierarchical instance being processed
|
||||||
|
AstDot* m_dotp = nullptr; // Current dot being processed
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstConfig* nodep) override {
|
void visit(AstConfig* nodep) override {
|
||||||
const string fullTopName = v3Global.opt.work() + '.' + v3Global.opt.topModule();
|
VL_RESTORER(m_isTop);
|
||||||
const bool topMatch = (fullTopName == nodep->name());
|
const auto& fullName = std::pair<std::string, std::string>{nodep->libname(), nodep->configname()};
|
||||||
if (topMatch) {
|
m_isTop = std::find(m_state.m_designs.begin(), m_state.m_designs.end(), fullName) != m_state.m_designs.end();
|
||||||
m_state.m_topModuleNames.erase(fullTopName);
|
m_state.m_designs.erase(
|
||||||
for (AstConfigCell* cellp = nodep->designp(); cellp;
|
std::remove(m_state.m_designs.begin(), m_state.m_designs.end(), fullName),
|
||||||
cellp = VN_AS(cellp->nextp(), ConfigCell)) {
|
m_state.m_designs.end());
|
||||||
m_state.m_topModuleNames.insert(cellp->name());
|
iterateChildren(nodep);
|
||||||
}
|
|
||||||
}
|
|
||||||
// We don't do iterateChildren here because we want to skip designp
|
|
||||||
iterateAndNextNull(nodep->itemsp());
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(AstConfigCell* nodep) override {
|
||||||
|
if (m_isTop) m_state.m_designs.emplace_back(nodep->libname(), nodep->cellname());
|
||||||
|
}
|
||||||
|
|
||||||
void visit(AstConfigRule* nodep) override {
|
void visit(AstConfigRule* nodep) override {
|
||||||
if (!nodep->cellp()) {
|
if (!nodep->cellp()) {
|
||||||
for (AstNode* usep = nodep->usep(); usep; usep = usep->nextp()) {
|
VL_RESTORER(m_isDefault);
|
||||||
m_state.m_liblistDefault.push_back(usep->name());
|
m_isDefault = true;
|
||||||
}
|
iterateAndNextNull(nodep->usep());
|
||||||
} else if (nodep->isCell()) {
|
} else if (nodep->isCell()) {
|
||||||
string cellName = nodep->cellp()->name();
|
VL_RESTORER(m_cell);
|
||||||
if (VN_IS(nodep->usep(), ParseRef)) {
|
m_cell = nodep->cellp()->name();
|
||||||
m_state.m_liblistCell[cellName] = std::vector<std::string>{};
|
iterateAndNextNull(nodep->usep());
|
||||||
for (AstParseRef* usep = VN_AS(nodep->usep(), ParseRef); usep;
|
|
||||||
usep = VN_AS(usep->nextp(), ParseRef)) {
|
|
||||||
m_state.m_liblistCell[cellName].push_back(usep->name());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
m_state.m_uselistCell[cellName]
|
VL_RESTORER(m_hierInst);
|
||||||
= std::vector<std::pair<std::string, std::string>>{};
|
{
|
||||||
for (AstConfigUse* usep = VN_AS(nodep->usep(), ConfigUse); usep;
|
VL_RESTORER(m_dotp);
|
||||||
usep = VN_AS(usep->nextp(), ConfigUse)) {
|
m_dotp = VN_AS(nodep->cellp(), Dot);
|
||||||
m_state.m_uselistCell[cellName].push_back(
|
iterateAndNextNull(nodep->cellp());
|
||||||
std::pair<std::string, std::string>{usep->libname(), usep->cellname()});
|
}
|
||||||
|
iterateAndNextNull(nodep->usep());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (VN_IS(nodep->usep(), ParseRef)) {
|
void visit(AstDot* nodep) override {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: config inst liblist rule");
|
iterateChildren(nodep);
|
||||||
} else {
|
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: config inst use rule");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(AstParseRef* nodep) override {
|
||||||
|
if (m_isDefault) {
|
||||||
|
m_state.m_liblistDefault.emplace_back(nodep->name());
|
||||||
|
} else if (!m_cell.empty()) {
|
||||||
|
m_state.m_liblistCell[m_cell].emplace_back(nodep->name());
|
||||||
|
} else if (m_dotp) {
|
||||||
|
m_hierInst += m_hierInst.empty() ? nodep->name() : '.' + nodep->name();
|
||||||
|
} else if (!m_hierInst.empty()) {
|
||||||
|
m_state.m_liblistInst[m_hierInst].emplace_back(nodep->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstConfigUse* nodep) override {
|
||||||
|
if (nodep->isConfig()) {
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: hierarchical config rule");
|
||||||
|
} else if (!m_cell.empty()) {
|
||||||
|
m_state.m_uselistCell[m_cell].emplace_back(nodep->libname(), nodep->cellname());
|
||||||
|
} else if (m_dotp) {
|
||||||
|
m_hierInst += m_hierInst.empty() ? nodep->name() : '.' + nodep->name();
|
||||||
|
} else if (!m_hierInst.empty()) {
|
||||||
|
m_state.m_uselistInst[m_hierInst].emplace_back(
|
||||||
|
nodep->libname(), nodep->cellname());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,9 +201,8 @@ public:
|
||||||
LinkConfigsVisitor(AstNetlist* nodep, LinkCellsState& state)
|
LinkConfigsVisitor(AstNetlist* nodep, LinkCellsState& state)
|
||||||
: m_state{state} {
|
: m_state{state} {
|
||||||
// Initialize top module from command line option
|
// Initialize top module from command line option
|
||||||
if (!m_state.m_topModuleNames.size() && !v3Global.opt.topModule().empty()) {
|
if (!m_state.m_designs.size() && !v3Global.opt.topModule().empty()) {
|
||||||
const string fullTopName = v3Global.opt.work() + '.' + v3Global.opt.topModule();
|
m_state.m_designs.emplace_back(v3Global.opt.work(), v3Global.opt.topModule());
|
||||||
m_state.m_topModuleNames.insert(fullTopName);
|
|
||||||
}
|
}
|
||||||
iterate(nodep);
|
iterate(nodep);
|
||||||
}
|
}
|
||||||
|
|
@ -206,6 +244,10 @@ class LinkCellsVisitor final : public VNVisitor {
|
||||||
const V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable};
|
const V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable};
|
||||||
UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name());
|
UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name());
|
||||||
}
|
}
|
||||||
|
void cellEdge(V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cuttable, AstCell* cellp) {
|
||||||
|
const V3GraphEdge* const edgep = new CellEdge{&m_graph, fromp, top, weight, cuttable, cellp};
|
||||||
|
UINFO(9, " cellEdge " << edgep << " " << fromp->name() << " -> " << top->name());
|
||||||
|
}
|
||||||
void insertModInLib(const string& name, const string& libname, AstNodeModule* nodep) {
|
void insertModInLib(const string& name, const string& libname, AstNodeModule* nodep) {
|
||||||
// Be able to find the module under it's library using the name it was given
|
// Be able to find the module under it's library using the name it was given
|
||||||
VSymEnt* libSymp = m_mods.rootp()->findIdFlat(libname);
|
VSymEnt* libSymp = m_mods.rootp()->findIdFlat(libname);
|
||||||
|
|
@ -292,10 +334,78 @@ class LinkCellsVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstCell* findCellByHier(AstNetlist* nodep, const std::string& hierPath) {
|
||||||
|
std::stringstream ss(hierPath);
|
||||||
|
std::string top;
|
||||||
|
bool topFound = false;
|
||||||
|
std::getline(ss, top, '.');
|
||||||
|
for (auto const& pair : m_state.m_designs) {
|
||||||
|
if (top == pair.second) {
|
||||||
|
topFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!topFound) {
|
||||||
|
nodep->v3error("Can't find top-level module for instance path: '" << hierPath << "'");
|
||||||
|
V3Error::abortIfErrors();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const V3GraphVertex* vtx = m_topVertexp;
|
||||||
|
const CellEdge* finalEdgep = nullptr;
|
||||||
|
std::string seg;
|
||||||
|
while (std::getline(ss, seg, '.')) {
|
||||||
|
finalEdgep = nullptr;
|
||||||
|
for (const V3GraphEdge& edge : vtx->outEdges()) {
|
||||||
|
if (const CellEdge* const cedgep = edge.cast<CellEdge>()) {
|
||||||
|
if (cedgep->cellp()->name() == seg) {
|
||||||
|
vtx = cedgep->top();
|
||||||
|
finalEdgep = cedgep;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!finalEdgep) return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalEdgep->cellp();
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNetlist* nodep) override {
|
void visit(AstNetlist* nodep) override {
|
||||||
readModNames();
|
readModNames();
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
||||||
|
// Replace instance module pointers based on config
|
||||||
|
AstNodeModule* modp = nullptr;
|
||||||
|
AstCell* cellp = nullptr;
|
||||||
|
|
||||||
|
// Search liblists for each instance
|
||||||
|
for (auto const& pair : m_state.m_liblistInst) {
|
||||||
|
cellp = findCellByHier(nodep, pair.first);
|
||||||
|
if (!cellp) continue;
|
||||||
|
for (auto const& libname : pair.second) {
|
||||||
|
modp = findModuleLibSym(cellp->modName(), libname);
|
||||||
|
if (modp) {
|
||||||
|
cellp->modp(modp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search uselists for each instance
|
||||||
|
for (auto const& pair : m_state.m_uselistInst) {
|
||||||
|
cellp = findCellByHier(nodep, pair.first);
|
||||||
|
for (auto const& u : pair.second) {
|
||||||
|
modp = findModuleLibSym(u.second, u.first);
|
||||||
|
if (modp) {
|
||||||
|
cellp->modp(modp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find levels in graph
|
// Find levels in graph
|
||||||
m_graph.removeRedundantEdgesMax(&V3GraphEdge::followAlwaysTrue);
|
m_graph.removeRedundantEdgesMax(&V3GraphEdge::followAlwaysTrue);
|
||||||
if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed("linkcells");
|
if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed("linkcells");
|
||||||
|
|
@ -348,8 +458,9 @@ class LinkCellsVisitor final : public VNVisitor {
|
||||||
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) {
|
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) {
|
||||||
nodep->inLibrary(true); // Interfaces can't be at top, unless asked
|
nodep->inLibrary(true); // Interfaces can't be at top, unless asked
|
||||||
}
|
}
|
||||||
const string fullName = nodep->libname() + "." + nodep->name();
|
|
||||||
const bool topMatch = (m_state.m_topModuleNames.count(fullName) > 0);
|
auto const& fullName = std::pair<std::string, std::string>(nodep->libname(), nodep->name());
|
||||||
|
const bool topMatch = std::find(m_state.m_designs.begin(), m_state.m_designs.end(), fullName) != m_state.m_designs.end();
|
||||||
if (topMatch) {
|
if (topMatch) {
|
||||||
m_topVertexp = vertex(nodep);
|
m_topVertexp = vertex(nodep);
|
||||||
UINFO(2, "Link --top-module: " << nodep);
|
UINFO(2, "Link --top-module: " << nodep);
|
||||||
|
|
@ -507,7 +618,7 @@ class LinkCellsVisitor final : public VNVisitor {
|
||||||
} else { // Non-recursive
|
} else { // Non-recursive
|
||||||
// Track module depths, so can sort list from parent down to children
|
// Track module depths, so can sort list from parent down to children
|
||||||
nodep->modp(cellmodp);
|
nodep->modp(cellmodp);
|
||||||
newEdge(vertex(m_modp), vertex(cellmodp), 1, false);
|
cellEdge(vertex(m_modp), vertex(cellmodp), 1, false, nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
%Error-UNSUPPORTED: t/t_config_hier.v:36:3: Unsupported: config inst use rule
|
%Error-UNSUPPORTED: t/t_config_hier.v:36:18: Unsupported: hierarchical config rule
|
||||||
36 | instance t.u_1 use work.cfg2 :config;
|
36 | instance t.u_1 use work.cfg2 :config;
|
||||||
| ^~~~~~~~
|
| ^~~
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||||
%Error-UNSUPPORTED: t/t_config_hier.v:41:3: Unsupported: config inst use rule
|
%Error-UNSUPPORTED: t/t_config_hier.v:41:18: Unsupported: hierarchical config rule
|
||||||
41 | instance t.u_1 use cfg2 :config;
|
41 | instance t.u_1 use cfg2 :config;
|
||||||
| ^~~~~~~~
|
| ^~~
|
||||||
%Error-UNSUPPORTED: t/t_config_hier.v:62:3: Unsupported: config inst use rule
|
%Error-UNSUPPORTED: t/t_config_hier.v:46:16: Unsupported: hierarchical config rule
|
||||||
62 | instance u_bb use work.c2_bb;
|
46 | cell work.m1 use work.cfg2 :config;
|
||||||
| ^~~~~~~~
|
| ^~~
|
||||||
|
%Error-UNSUPPORTED: t/t_config_hier.v:51:11: Unsupported: hierarchical config rule
|
||||||
|
51 | cell m1 use cfg2 :config;
|
||||||
|
| ^~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -59,5 +59,5 @@ endconfig
|
||||||
// Base usage
|
// Base usage
|
||||||
config cfg2;
|
config cfg2;
|
||||||
design c2_b;
|
design c2_b;
|
||||||
instance u_bb use work.c2_bb;
|
instance c2_b.u_bb use work.c2_bb;
|
||||||
endconfig
|
endconfig
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
*-* All Finished *-*
|
||||||
|
liba:m1 %m=t.u_1 %l=liba.m1
|
||||||
|
liba:m3 %m=t.u_2.u_23 %l=liba.m3
|
||||||
|
libb:m2 %m=t.u_2 %l=libb.m2
|
||||||
|
libb:m3 %m=t.u_1.u_13 %l=libb.m3
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=[
|
||||||
|
'--binary', '--top cfg1', '--work liba', 't/t_config_work__liba.v', '--work libb',
|
||||||
|
't/t_config_work__libb.v'
|
||||||
|
])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
# Sort so that 'initial' scheduling order is not relevant
|
||||||
|
test.files_identical_sorted(test.run_log_filename, test.golden_filename, is_logfile=True)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
// Test config allows selecting two different libraries for these instances
|
||||||
|
m1 u_1();
|
||||||
|
m2 u_2();
|
||||||
|
final $write("*-* All Finished *-*\n");
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
config cfg1;
|
||||||
|
design t;
|
||||||
|
// Use libb's version of m3 for m1 and liba's version of m3 for m2
|
||||||
|
instance t.u_1.u_13 liblist libb;
|
||||||
|
instance t.u_2.u_23 use liba.m3;
|
||||||
|
endconfig
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
%Error: Can't find top-level module for instance path: 't2.u_2.u_23'
|
||||||
|
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -9,8 +9,11 @@
|
||||||
|
|
||||||
import vltest_bootstrap
|
import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('vlt')
|
test.scenarios('simulator')
|
||||||
|
|
||||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
test.lint(verilator_flags2=[
|
||||||
|
'--binary', '--top cfg1', '--work liba', 't/t_config_work__liba.v', '--work libb',
|
||||||
|
't/t_config_work__libb.v'
|
||||||
|
], fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
// Test config allows selecting two different libraries for these instances
|
||||||
|
m1 u_1();
|
||||||
|
m2 u_2();
|
||||||
|
final $write("*-* All Finished *-*\n");
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
config cfg1;
|
||||||
|
design t;
|
||||||
|
// Use libb's version of m3 for m1 and liba's version of m3 for m2
|
||||||
|
instance t.u_1.u_13 liblist libb;
|
||||||
|
// t2 not found, causes error
|
||||||
|
instance t2.u_2.u_23 use liba.m3;
|
||||||
|
endconfig
|
||||||
|
|
@ -15,13 +15,8 @@ test.compile(verilator_flags2=[
|
||||||
"--binary", "--top cfg", "--work liba t/t_config_rules_sub.v",
|
"--binary", "--top cfg", "--work liba t/t_config_rules_sub.v",
|
||||||
"--work libb t/t_config_rules_sub.v", "--work libc t/t_config_rules_sub.v",
|
"--work libb t/t_config_rules_sub.v", "--work libc t/t_config_rules_sub.v",
|
||||||
"--work libd t/t_config_rules_sub.v"
|
"--work libd t/t_config_rules_sub.v"
|
||||||
],
|
])
|
||||||
fails=True,
|
|
||||||
expect_filename=test.golden_filename)
|
|
||||||
|
|
||||||
#test.execute()
|
test.execute()
|
||||||
|
|
||||||
# Sort so that 'initial' scheduling order is not relevant
|
|
||||||
#test.files_identical_sorted(test.run_log_filename, test.golden_filename, is_logfile=True)
|
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:32:3: Unsupported: config inst use rule
|
|
||||||
32 | instance t.m20 liblist;
|
|
||||||
| ^~~~~~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:33:3: Unsupported: config inst liblist rule
|
|
||||||
33 | instance t.m21 liblist libc;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:34:3: Unsupported: config inst liblist rule
|
|
||||||
34 | instance t.m22 liblist libc libd;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:35:3: Unsupported: config inst liblist rule
|
|
||||||
35 | instance t.m23 liblist libc libd;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:36:3: Unsupported: config inst liblist rule
|
|
||||||
36 | instance t.m24 liblist libc libd;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:39:3: Unsupported: config inst use rule
|
|
||||||
39 | instance t.m30 use cell_identifier;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:40:3: Unsupported: config inst use rule
|
|
||||||
40 | instance t.m31 use lib_id.cell_id;
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_config_unsup.v:41:3: Unsupported: config inst use rule
|
|
||||||
41 | instance t.m32 use #();
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
// DESCRIPTION: Verilator: Verilog Test module
|
|
||||||
//
|
|
||||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
||||||
// any use, without warranty, 2025 by Wilson Snyder.
|
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
module t;
|
|
||||||
m10 u_10();
|
|
||||||
m20 u_20();
|
|
||||||
m21 u_21();
|
|
||||||
m22 u_22();
|
|
||||||
m23 u_23();
|
|
||||||
m24 u_24();
|
|
||||||
m30 u_30();
|
|
||||||
m31 u_31();
|
|
||||||
m32 u_32();
|
|
||||||
m40 u_40();
|
|
||||||
m41 u_41();
|
|
||||||
m42 u_42();
|
|
||||||
m43 u_43();
|
|
||||||
final $write("*-* All Finished *-*\n");
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
config cfg;
|
|
||||||
design t;
|
|
||||||
|
|
||||||
// Test uses m10
|
|
||||||
default liblist; // Ignored
|
|
||||||
default liblist liba libb;
|
|
||||||
|
|
||||||
// Test uses m20-29
|
|
||||||
instance t.m20 liblist; // Use parent's cell library
|
|
||||||
instance t.m21 liblist libc;
|
|
||||||
instance t.m22 liblist libc libd; // m22 in libc
|
|
||||||
instance t.m23 liblist libc libd; // m23 in libd
|
|
||||||
instance t.m24 liblist libc libd; // m24 in default (libb)
|
|
||||||
|
|
||||||
// Test uses m30-39
|
|
||||||
instance t.m30 use cell_identifier;
|
|
||||||
instance t.m31 use lib_id.cell_id;
|
|
||||||
instance t.m32 use #();
|
|
||||||
|
|
||||||
// Test uses m40-49
|
|
||||||
cell m40 liblist libc libd;
|
|
||||||
cell work.m41 liblist libc libd;
|
|
||||||
cell m42 use m42alt;
|
|
||||||
cell work.m43 use work.m43alt;
|
|
||||||
|
|
||||||
endconfig
|
|
||||||
Loading…
Reference in New Issue