Skip to content

Commit 1077161

Browse files
committed
odb: Replace insert buffer scalar brackets
Replace bracket characters with underscores in generated insert buffer scalar hierarchy port and split-net names. The generated names are scalar objects, not bus ports or bus nets, so preserving raw bracket syntax is unnecessary and can confuse name-only consumers. Replacing brackets keeps the emitted Verilog readable while avoiding bus-bit interpretation. Add Tcl and C++ regressions for hierarchy punch-through and bus-bit-derived split net naming. Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
1 parent 8eade99 commit 1077161

7 files changed

Lines changed: 343 additions & 1 deletion

src/dbSta/test/cpp/TestReadVerilog.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,74 @@ TEST_F(TestReadVerilog, DeepDescendantModBTermCollision)
185185
EXPECT_EQ(txclk_modnet->getModBTerms().size(), 1u);
186186
}
187187

188+
TEST_F(TestReadVerilog, EscapedBracketScalarNames)
189+
{
190+
const testing::TestInfo* test_info
191+
= testing::UnitTest::GetInstance()->current_test_info();
192+
const std::string test_name
193+
= std::string(test_info->test_suite_name()) + "_" + test_info->name();
194+
195+
readVerilogAndSetup(test_name + ".v", /*init_default_sdc=*/false);
196+
197+
odb::dbBTerm* raw_bterm = block_->findBTerm("foo[3]");
198+
odb::dbBTerm* leading_escape_bterm = block_->findBTerm("\\foo[3]");
199+
odb::dbBTerm* escaped_bterm = block_->findBTerm("foo\\[3\\]");
200+
EXPECT_EQ(raw_bterm, nullptr);
201+
EXPECT_EQ(leading_escape_bterm, nullptr);
202+
ASSERT_NE(escaped_bterm, nullptr);
203+
EXPECT_STREQ(escaped_bterm->getConstName(), "foo\\[3\\]");
204+
205+
odb::dbModule* child = block_->findModule("child");
206+
ASSERT_NE(child, nullptr);
207+
208+
EXPECT_EQ(child->findModBTerm("foo[3]"), nullptr);
209+
EXPECT_EQ(child->findModBTerm("\\foo[3]"), nullptr);
210+
odb::dbModBTerm* escaped_modbterm = child->findModBTerm("foo\\[3\\]");
211+
ASSERT_NE(escaped_modbterm, nullptr);
212+
213+
EXPECT_EQ(child->getModNet("foo[3]"), nullptr);
214+
EXPECT_EQ(child->getModNet("\\foo[3]"), nullptr);
215+
odb::dbModNet* escaped_modnet = child->getModNet("foo\\[3\\]");
216+
ASSERT_NE(escaped_modnet, nullptr);
217+
EXPECT_EQ(escaped_modbterm->getModNet(), escaped_modnet);
218+
}
219+
220+
TEST_F(TestReadVerilog, BusBitAndEscapedScalarAreDistinct)
221+
{
222+
const testing::TestInfo* test_info
223+
= testing::UnitTest::GetInstance()->current_test_info();
224+
const std::string test_name
225+
= std::string(test_info->test_suite_name()) + "_" + test_info->name();
226+
227+
readVerilogAndSetup(test_name + ".v", /*init_default_sdc=*/false);
228+
229+
odb::dbBTerm* bus_bit_bterm = block_->findBTerm("foo[3]");
230+
odb::dbBTerm* leading_escape_bterm = block_->findBTerm("\\foo[3]");
231+
odb::dbBTerm* escaped_bterm = block_->findBTerm("foo\\[3\\]");
232+
ASSERT_NE(bus_bit_bterm, nullptr);
233+
EXPECT_EQ(leading_escape_bterm, nullptr);
234+
ASSERT_NE(escaped_bterm, nullptr);
235+
EXPECT_NE(bus_bit_bterm, escaped_bterm);
236+
237+
odb::dbModule* child = block_->findModule("child");
238+
ASSERT_NE(child, nullptr);
239+
240+
odb::dbModBTerm* bus_port = child->findModBTerm("foo");
241+
odb::dbModBTerm* bus_bit_port = child->findModBTerm("foo[3]");
242+
odb::dbModBTerm* escaped_port = child->findModBTerm("foo\\[3\\]");
243+
ASSERT_NE(bus_port, nullptr);
244+
ASSERT_NE(bus_bit_port, nullptr);
245+
EXPECT_EQ(child->findModBTerm("\\foo[3]"), nullptr);
246+
ASSERT_NE(escaped_port, nullptr);
247+
EXPECT_NE(bus_bit_port, escaped_port);
248+
249+
odb::dbModNet* bus_bit_modnet = child->getModNet("foo[3]");
250+
odb::dbModNet* escaped_modnet = child->getModNet("foo\\[3\\]");
251+
ASSERT_NE(bus_bit_modnet, nullptr);
252+
EXPECT_EQ(child->getModNet("\\foo[3]"), nullptr);
253+
ASSERT_NE(escaped_modnet, nullptr);
254+
EXPECT_NE(bus_bit_modnet, escaped_modnet);
255+
EXPECT_EQ(escaped_port->getModNet(), escaped_modnet);
256+
}
257+
188258
} // namespace sta
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module top (foo,
2+
\foo[3] ,
3+
out_bus,
4+
out_scalar);
5+
input [7:0] foo;
6+
input \foo[3] ;
7+
output out_bus;
8+
output out_scalar;
9+
10+
child u_child (.foo(foo),
11+
.\foo[3] (\foo[3] ),
12+
.out_bus(out_bus),
13+
.out_scalar(out_scalar));
14+
endmodule
15+
16+
module child (foo,
17+
\foo[3] ,
18+
out_bus,
19+
out_scalar);
20+
input [7:0] foo;
21+
input \foo[3] ;
22+
output out_bus;
23+
output out_scalar;
24+
25+
BUF_X1 bus_load (.A(foo[3]),
26+
.Z(out_bus));
27+
BUF_X1 scalar_load (.A(\foo[3] ),
28+
.Z(out_scalar));
29+
endmodule
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module top (\foo[3] ,
2+
out);
3+
input \foo[3] ;
4+
output out;
5+
6+
child u_child (.\foo[3] (\foo[3] ),
7+
.out(out));
8+
endmodule
9+
10+
module child (\foo[3] ,
11+
out);
12+
input \foo[3] ;
13+
output out;
14+
15+
BUF_X1 load (.A(\foo[3] ),
16+
.Z(out));
17+
endmodule

src/odb/src/db/dbInsertBuffer.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@
2424

2525
namespace odb {
2626

27+
static std::string replaceBracketsWithUnderscores(std::string_view name)
28+
{
29+
std::string sanitized_name;
30+
sanitized_name.reserve(name.size());
31+
32+
for (size_t i = 0; i < name.size(); i++) {
33+
const char ch = name[i];
34+
if (ch == '\\' && i + 1 < name.size()
35+
&& (name[i + 1] == '[' || name[i + 1] == ']')) {
36+
sanitized_name += '_';
37+
i++;
38+
continue;
39+
}
40+
sanitized_name += (ch == '[' || ch == ']') ? '_' : ch;
41+
}
42+
43+
return sanitized_name;
44+
}
45+
2746
dbInsertBuffer::dbInsertBuffer(dbNet* net)
2847
: net_(net),
2948
block_(net ? net->getBlock() : nullptr),
@@ -495,6 +514,12 @@ dbNet* dbInsertBuffer::createNewFlatNet(
495514
new_net_uniquify = dbNameUniquifyType::IF_NEEDED;
496515
}
497516

517+
if (bterm == nullptr) {
518+
// New split nets are scalar wires. Keep their generated names easy to read
519+
// by replacing bracket characters before ODB stores the name.
520+
new_net_name = replaceBracketsWithUnderscores(new_net_name);
521+
}
522+
498523
// Create a new net
499524
dbNet* new_net = dbNet::create(
500525
block_, new_net_name.c_str(), new_net_uniquify, target_module_);
@@ -513,7 +538,10 @@ std::string dbInsertBuffer::makeUniqueHierName(const dbModule* module,
513538
const std::string& base_name,
514539
const char* suffix) const
515540
{
516-
std::string name = (suffix == nullptr) ? base_name : base_name + suffix;
541+
// insertBuffer only punches scalar hierarchy ports, never bus ports.
542+
std::string scalar_base_name = replaceBracketsWithUnderscores(base_name);
543+
std::string name
544+
= (suffix == nullptr) ? scalar_base_name : scalar_base_name + suffix;
517545
std::string full = block_->makeNewNetName(
518546
module, name.c_str(), dbNameUniquifyType::IF_NEEDED_WITH_UNDERSCORE);
519547
return std::string(block_->getBaseName(full.c_str()));

src/rsz/test/cpp/TestInsertBuffer.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,4 +3371,103 @@ TEST_F(TestInsertBuffer, BeforeLoads_Case34)
33713371
writeAndCompareVerilogOutputFile(test_name, test_name + "_post.v");
33723372
}
33733373

3374+
TEST_F(TestInsertBuffer, BusBitModNetName)
3375+
{
3376+
const auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
3377+
const std::string test_name
3378+
= std::string(test_info->test_suite_name()) + "_" + test_info->name();
3379+
3380+
int num_warning = 0;
3381+
readVerilogAndSetup(test_name + "_pre.v");
3382+
3383+
dbMaster* buf_master = db_->findMaster("BUF_X4");
3384+
ASSERT_NE(buf_master, nullptr);
3385+
3386+
dbModule* sub_mod = block_->findModule("SUB");
3387+
ASSERT_NE(sub_mod, nullptr);
3388+
3389+
EXPECT_NE(block_->findBTerm("foo[3]"), nullptr);
3390+
EXPECT_EQ(block_->findBTerm("\\foo[3]"), nullptr);
3391+
EXPECT_NE(sub_mod->findModBTerm("foo[3]"), nullptr);
3392+
EXPECT_EQ(sub_mod->findModBTerm("foo\\[3\\]"), nullptr);
3393+
EXPECT_EQ(sub_mod->getModNet("foo[3]1"), nullptr);
3394+
EXPECT_EQ(sub_mod->getModNet("foo\\[3\\]"), nullptr);
3395+
3396+
dbNet* flat_net = block_->findNet("foo[3]");
3397+
ASSERT_NE(flat_net, nullptr);
3398+
dbITerm* load0_a = block_->findITerm("sub0/load0/A");
3399+
ASSERT_NE(load0_a, nullptr);
3400+
ASSERT_EQ(load0_a->getNet(), flat_net);
3401+
dbITerm* load1_a = block_->findITerm("sub0/child0/load1/A");
3402+
ASSERT_NE(load1_a, nullptr);
3403+
ASSERT_EQ(load1_a->getNet(), flat_net);
3404+
3405+
odb::PtrSet<dbObject> load_pins;
3406+
load_pins.insert(load0_a);
3407+
load_pins.insert(load1_a);
3408+
3409+
dbInst* new_buf
3410+
= flat_net->insertBufferBeforeLoads(load_pins,
3411+
buf_master,
3412+
nullptr,
3413+
"split",
3414+
"foo[3]",
3415+
dbNameUniquifyType::IF_NEEDED,
3416+
false);
3417+
ASSERT_NE(new_buf, nullptr);
3418+
3419+
sta_->updateTiming(true);
3420+
num_warning = db_network_->checkAxioms();
3421+
num_warning += sta_->checkSanity();
3422+
EXPECT_EQ(num_warning, 0);
3423+
3424+
std::string mod_net_names;
3425+
for (dbModNet* mod_net : sub_mod->getModNets()) {
3426+
if (!mod_net_names.empty()) {
3427+
mod_net_names += ", ";
3428+
}
3429+
mod_net_names += mod_net->getConstName();
3430+
}
3431+
3432+
EXPECT_NE(sub_mod->getModNet("foo_3_"), nullptr)
3433+
<< "The split net is a scalar wire, so bracket characters should be "
3434+
"replaced in the stored dbModNet name. Existing dbModNet names: "
3435+
<< mod_net_names;
3436+
3437+
writeAndCompareVerilogOutputFile(test_name, test_name + "_post.v");
3438+
}
3439+
3440+
TEST_F(TestInsertBuffer, BusBitBTermName)
3441+
{
3442+
dbMaster* buf_master = db_->findMaster("BUF_X4");
3443+
ASSERT_NE(buf_master, nullptr);
3444+
3445+
dbNet* orig_net = dbNet::create(block_, "orig");
3446+
ASSERT_NE(orig_net, nullptr);
3447+
dbBTerm* bterm = dbBTerm::create(orig_net, "foo[3]");
3448+
ASSERT_NE(bterm, nullptr);
3449+
bterm->setIoType(dbIoType::OUTPUT);
3450+
bterm->connect(orig_net);
3451+
3452+
dbInst* drvr = dbInst::create(block_, db_->findMaster("LOGIC0_X1"), "drvr");
3453+
ASSERT_NE(drvr, nullptr);
3454+
dbITerm* drvr_z = drvr->findITerm("Z");
3455+
ASSERT_NE(drvr_z, nullptr);
3456+
drvr_z->connect(orig_net);
3457+
3458+
dbInst* new_buf
3459+
= orig_net->insertBufferBeforeLoad(bterm, buf_master, nullptr, "output");
3460+
ASSERT_NE(new_buf, nullptr);
3461+
3462+
dbITerm* buf_z = new_buf->findITerm("Z");
3463+
ASSERT_NE(buf_z, nullptr);
3464+
dbNet* buf_out_net = buf_z->getNet();
3465+
ASSERT_NE(buf_out_net, nullptr);
3466+
3467+
EXPECT_EQ(bterm->getNet(), buf_out_net);
3468+
EXPECT_STREQ(buf_out_net->getConstName(), "foo[3]")
3469+
<< "BTerm-derived net names must preserve the port name for Verilog "
3470+
"compatibility.";
3471+
}
3472+
33743473
} // namespace odb
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
module top (out0,
2+
out1,
3+
out2,
4+
foo);
5+
output out0;
6+
output out1;
7+
output out2;
8+
input [7:0] foo;
9+
10+
11+
SUB sub0 (.foo({foo[7],
12+
foo[6],
13+
foo[5],
14+
foo[4],
15+
foo[3],
16+
foo[2],
17+
foo[1],
18+
foo[0]}),
19+
.out0(out0),
20+
.out1(out1),
21+
.out2(out2));
22+
endmodule
23+
module CHILD (foo,
24+
Z);
25+
input [7:0] foo;
26+
output Z;
27+
28+
29+
BUF_X1 load1 (.A(foo[3]),
30+
.Z(Z));
31+
endmodule
32+
module SUB (foo,
33+
out0,
34+
out1,
35+
out2);
36+
input [7:0] foo;
37+
output out0;
38+
output out1;
39+
output out2;
40+
41+
wire foo_3_;
42+
43+
CHILD child0 (.foo({foo[7],
44+
foo[6],
45+
foo[5],
46+
foo[4],
47+
foo_3_,
48+
foo[2],
49+
foo[1],
50+
foo[0]}),
51+
.Z(out1));
52+
BUF_X1 load0 (.A(foo_3_),
53+
.Z(out0));
54+
BUF_X1 load2 (.A(foo[3]),
55+
.Z(out2));
56+
BUF_X4 split (.A(foo[3]),
57+
.Z(foo_3_));
58+
endmodule
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module top (foo,
2+
out0,
3+
out1,
4+
out2);
5+
input [7:0] foo;
6+
output out0;
7+
output out1;
8+
output out2;
9+
10+
11+
SUB sub0 (.foo(foo),
12+
.out0(out0),
13+
.out1(out1),
14+
.out2(out2));
15+
endmodule
16+
module SUB (foo,
17+
out0,
18+
out1,
19+
out2);
20+
input [7:0] foo;
21+
output out0;
22+
output out1;
23+
output out2;
24+
25+
26+
BUF_X1 load0 (.A(foo[3]),
27+
.Z(out0));
28+
CHILD child0 (.foo(foo),
29+
.Z(out1));
30+
BUF_X1 load2 (.A(foo[3]),
31+
.Z(out2));
32+
endmodule
33+
module CHILD (foo,
34+
Z);
35+
input [7:0] foo;
36+
output Z;
37+
38+
39+
BUF_X1 load1 (.A(foo[3]),
40+
.Z(Z));
41+
endmodule

0 commit comments

Comments
 (0)