Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/dbSta/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ALL_TESTS = [
"hierclock",
"hierwrite",
"hier_deep",
"hier_weird_port",
"make_port",
"network_edit1",
"power1",
Expand Down
1 change: 1 addition & 0 deletions src/dbSta/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ or_integration_tests(
hierclock
hierwrite
hier_deep
hier_weird_port
make_port
network_edit1
power1
Expand Down
25 changes: 25 additions & 0 deletions src/dbSta/test/hier_weird_port.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[INFO ODB-0227] LEF file: liberty1.lef, created 2 layers, 6 library cells
[WARNING ORD-0011] Hierarchical flow (-hier) is currently in development and may cause multiple issues. Do not use in production environments.
[WARNING ORD-2056] The following 11 liberty cell(s) do not have LEF masters and will be marked as dont-use:
snl_ff2x1
snl_invx2
snl_lenqnx1
snl_lqx1
snl_mux21x1
snl_nand02x1
snl_nand02x2
snl_oa012x1
snl_or02x1
snl_tbufx1
snl_xor2x1
Warning: There is 1 input port missing set_input_delay.
in1
Warning: There is 1 output port missing set_output_delay.
out1
Warning: There is 1 unconstrained endpoint.
out1
modinst 'u_sub' master 'sub':
head modbterm: 'path\/with\/slash'
--- pin-direction on u_sub ---
u_sub/out dir=output
u_sub/slash dir=input
32 changes: 32 additions & 0 deletions src/dbSta/test/hier_weird_port.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Regression for dbModule::findModBTerm handling of modbterms whose stored
# name contains '/' characters (as produced when Fusion Compiler emits an
# escaped-identifier port name into the netlist). Before the findModBTerm
# fix, the pin-direction resolution below would call findModBTerm with the
# full name, get unconditionally truncated to the trailing segment in the
# lookup, miss, and crash on a null modbterm in dbNetwork::direction.
source "helpers.tcl"
read_lef liberty1.lef
read_liberty liberty1.lib
read_verilog hier_weird_port.v
link_design top -hier

# This was the call path that crashed on the ebrick_south flow.
check_setup -verbose

# Confirm the modbterm is stored with '/' chars preserved.
set block [ord::get_db_block]
set top_mod [$block getTopModule]
foreach child [$top_mod getChildren] {
set master [$child getMaster]
puts "modinst '[$child getName]' master '[$master getName]':"
set mbt [$master getHeadDbModBTerm]
if { $mbt != "NULL" } {
puts " head modbterm: '[$mbt getName]'"
}
}

# Pin-direction resolution on u_sub.
puts "--- pin-direction on u_sub ---"
foreach pin [get_pins -hierarchical u_sub/*] {
puts " [get_property $pin full_name] dir=[get_property $pin direction]"
}
21 changes: 21 additions & 0 deletions src/dbSta/test/hier_weird_port.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Reproducer: Verilog escaped identifier containing '/' on a sub-module port.
// After read_verilog + link_design -hier, the modbterm on the sub master is
// stored with '/' as literal characters (backslash-escape preserved). Before
// the fix in src/odb/src/db/dbModule.cpp, dbModule::findModBTerm truncated
// names at the last '/' before hashing, so lookups of such modbterms missed.
// That miss crashed dbNetwork::direction in downstream graph construction.
// With the fix, pin-direction resolution succeeds.

module sub (\path/with/slash , out);
input \path/with/slash ;
output out;
wire intermediate;
snl_bufx1 u1 (.A(\path/with/slash ), .Z(intermediate));
snl_bufx1 u2 (.A(intermediate), .Z(out));
endmodule

module top (in1, out1);
input in1;
output out1;
sub u_sub (.\path/with/slash (in1), .out(out1));
endmodule
24 changes: 15 additions & 9 deletions src/odb/src/db/dbModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,18 +544,24 @@ std::vector<dbInst*> dbModule::getLeafInsts()

dbModBTerm* dbModule::findModBTerm(const char* name) const
{
std::string modbterm_name(name);
const char hier_delimiter = getOwner()->getHierarchyDelimiter();
size_t last_idx = modbterm_name.find_last_of(hier_delimiter);
if (last_idx != std::string::npos) {
modbterm_name = modbterm_name.substr(last_idx + 1);
}
const _dbModule* obj = (const _dbModule*) this;
const _dbBlock* par = (const _dbBlock*) obj->getOwner();
auto it = obj->modbterm_hash_.find(modbterm_name);

// Try the full name first. modbterm names may legitimately contain the
// hierarchy delimiter (e.g. escaped-identifier ports emitted by other
// EDA tools), so unconditionally truncating at the last '/' would miss
// them. Fall back to the trailing segment for callers that pass a
// hierarchical path to a non-hierarchical port name.
auto it = obj->modbterm_hash_.find(name);
if (it == obj->modbterm_hash_.end()) {
const char hier_delimiter = getOwner()->getHierarchyDelimiter();
const char* last_delim = strrchr(name, hier_delimiter);
if (last_delim != nullptr) {
it = obj->modbterm_hash_.find(last_delim + 1);
}
}
if (it != obj->modbterm_hash_.end()) {
auto db_id = (*it).second;
return (dbModBTerm*) par->modbterm_tbl_->getPtr(db_id);
return (dbModBTerm*) par->modbterm_tbl_->getPtr((*it).second);
}
return nullptr;
}
Expand Down
Loading