Skip to content

Commit 45f3037

Browse files
oharboeclaude
andcommitted
odb: makeNewNetName must avoid instance name collisions
dbBlock::makeNewNetName uniquified a new net/port name against ModNets, ModBTerms, and flat nets in the scope, but not against instance names. A net/port and an instance cannot share a name in one Verilog scope. OpenROAD's hierarchical flow promotes some anonymous nets ("_NNNNN_") to module boundary ports, and yosys/ABC name anonymous cells "_NNNNN_" too, so a promoted boundary port could be handed a name already owned by a leaf (dbInst) or hierarchical (dbModInst) instance in the same module. write_verilog then emits a module with a port and an instance of the same name -- illegal Verilog that Verilator rejects with "Instance has the same name as port", breaking gate-level (e.g. SAIF) simulation of the placed netlist. Extend the collision check in makeNewNetName to also reject names that match a dbModInst or dbInst in the scope, so the generated name is uniquified (suffixed) when it would collide with an instance. Add a TestModule regression covering both the leaf-instance and module-instance collision cases, plus the no-collision passthrough. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
1 parent 28a1229 commit 45f3037

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

src/odb/src/db/dbBlock.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3883,7 +3883,15 @@ std::string dbBlock::makeNewNetName(const dbModule* parent,
38833883
auto exists = [this, scope, corresponding_flat_net](const char* name) {
38843884
if (scope != nullptr) {
38853885
const char* base = getBaseName(name);
3886-
if (scope->getModNet(base) || scope->findModBTerm(base)) {
3886+
// A net/port name must also be unique against instance names in the
3887+
// scope: a net/port and an instance cannot share a name in one Verilog
3888+
// scope. OpenROAD can promote an anonymous net ("_NNNNN_") to a
3889+
// module boundary port, and yosys/ABC name anonymous cells "_NNNNN_"
3890+
// too, so without this check the promoted port collides with a leaf or
3891+
// hierarchical instance of the same name -- illegal Verilog that
3892+
// Verilator rejects with "Instance has the same name as port".
3893+
if (scope->getModNet(base) || scope->findModBTerm(base)
3894+
|| scope->findModInst(base) || scope->findDbInst(base)) {
38873895
return true;
38883896
}
38893897
}

src/odb/test/cpp/TestModule.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,39 @@ TEST_F(ModuleFixture, test_find_modinst)
291291
auto minst2 = odb::dbModInst::create(master1, master2, "minst2");
292292
EXPECT_EQ(block_->findModInst("minst1/minst2"), minst2);
293293
}
294+
295+
// makeNewNetName must not hand out a name that already belongs to an
296+
// instance in the scope: a net/port and an instance cannot share a name in
297+
// one Verilog scope. OpenROAD promotes anonymous nets ("_NNNNN_") to
298+
// module boundary ports, and yosys/ABC name anonymous cells "_NNNNN_" too,
299+
// so without an instance-name check the promoted port collides with a leaf
300+
// or hierarchical instance -- illegal Verilog ("Instance has the same name
301+
// as port").
302+
TEST_F(ModuleFixture, makeNewNetName_avoids_instance_collision)
303+
{
304+
auto top = block_->getTopModule();
305+
ASSERT_NE(top, nullptr);
306+
307+
// Leaf (dbInst) collision: an instance named "_42_" exists in scope.
308+
dbInst::create(block_, lib_->findMaster("and2"), "_42_");
309+
std::string leaf = block_->makeNewNetName(
310+
top, "_42_", dbNameUniquifyType::IF_NEEDED_WITH_UNDERSCORE);
311+
EXPECT_STRNE(block_->getBaseName(leaf.c_str()), "_42_")
312+
<< "net name must not collide with leaf instance '_42_'";
313+
314+
// Hierarchical (dbModInst) collision: a module instance named "_99_".
315+
auto master = dbModule::create(block_, "anon_master");
316+
dbModInst::create(top, master, "_99_");
317+
std::string hier = block_->makeNewNetName(
318+
top, "_99_", dbNameUniquifyType::IF_NEEDED_WITH_UNDERSCORE);
319+
EXPECT_STRNE(block_->getBaseName(hier.c_str()), "_99_")
320+
<< "net name must not collide with module instance '_99_'";
321+
322+
// No collision: a fresh name is returned unchanged.
323+
std::string fresh = block_->makeNewNetName(
324+
top, "no_collision_here", dbNameUniquifyType::IF_NEEDED_WITH_UNDERSCORE);
325+
EXPECT_STREQ(block_->getBaseName(fresh.c_str()), "no_collision_here");
326+
}
294327
class DetailedFixture : public SimpleDbFixture
295328
{
296329
protected:

0 commit comments

Comments
 (0)