Fix port-to-pin conversion for names containing slashes. (#463)

Use get_port_pin instead of find_pin on the port leaf name so escaped
hierarchical port names like level1/level2/level3 resolve correctly.
Also fix arglilst typo in get_port_pins_error.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Akash Levy 2026-07-31 13:06:10 -07:00 committed by GitHub
parent d0526b524b
commit 3f4b337e30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 144 additions and 10 deletions

View File

@ -108,7 +108,7 @@ proc parse_connect_pin { arg } {
set port [$pin port] set port [$pin port]
} elseif { $object_type == "Port" } { } elseif { $object_type == "Port" } {
# Explicit port arg - convert to pin. # Explicit port arg - convert to pin.
set pin [find_pin [get_name $arg]] set pin [get_port_pin $arg]
set inst [$pin instance] set inst [$pin instance]
set port [$pin port] set port [$pin port]
} else { } else {

View File

@ -226,7 +226,7 @@ proc parse_clk_inst_port_pin_arg { objects clks_var insts_var pins_var } {
set ports {} set ports {}
get_object_args $objects clks {} {} {} insts ports pins {} {} {} get_object_args $objects clks {} {} {} insts ports pins {} {} {}
foreach port $ports { foreach port $ports {
lappend pins [[top_instance] find_pin [get_name $port]] lappend pins [get_port_pin $port]
} }
} }
@ -238,7 +238,7 @@ proc parse_clk_port_pin_arg { objects clks_var pins_var } {
set ports {} set ports {}
get_object_args $objects clks {} {} {} {} ports pins {} {} {} get_object_args $objects clks {} {} {} {} ports pins {} {} {}
foreach port $ports { foreach port $ports {
lappend pins [[top_instance] find_pin [get_name $port]] lappend pins [get_port_pin $port]
} }
} }
@ -325,7 +325,7 @@ proc parse_inst_port_pin_arg { objects insts_var pins_var } {
set ports {} set ports {}
get_object_args $objects {} {} {} {} insts ports pins {} {} {} get_object_args $objects {} {} {} {} insts ports pins {} {} {}
foreach port $ports { foreach port $ports {
lappend pins [[top_instance] find_pin [get_name $port]] lappend pins [get_port_pin $port]
} }
} }
@ -347,7 +347,7 @@ proc parse_inst_port_pin_net_arg { objects insts_var pins_var nets_var } {
set nets {} set nets {}
get_object_args $objects {} {} {} {} insts ports pins nets {} {} get_object_args $objects {} {} {} {} insts ports pins nets {} {}
foreach port $ports { foreach port $ports {
lappend pins [[top_instance] find_pin [get_name $port]] lappend pins [get_port_pin $port]
} }
} }
@ -368,7 +368,7 @@ proc parse_port_pin_net_arg { objects pins_var nets_var } {
get_object_args $objects {} {} {} {} {} ports pins nets {} {} get_object_args $objects {} {} {} {} {} ports pins nets {} {}
foreach port $ports { foreach port $ports {
lappend pins [[top_instance] find_pin [get_name $port]] lappend pins [get_port_pin $port]
} }
} }
@ -857,7 +857,7 @@ proc get_port_pin_arg { arg_name arg warn_error } {
set pin $arg set pin $arg
} elseif { $object_type == "Port" } { } elseif { $object_type == "Port" } {
# Explicit port arg - convert to pin. # Explicit port arg - convert to pin.
set pin [find_pin [get_name $arg]] set pin [get_port_pin $arg]
} else { } else {
sta_warn_error 129 $warn_error "$arg_name type '$object_type' is not a pin or port." sta_warn_error 129 $warn_error "$arg_name type '$object_type' is not a pin or port."
} }
@ -868,7 +868,7 @@ proc get_port_pin_arg { arg_name arg warn_error } {
if { $port == "NULL" } { if { $port == "NULL" } {
set pin [find_pin $arg] set pin [find_pin $arg]
} else { } else {
set pin [$top_instance find_pin [get_name $port]] set pin [get_port_pin $port]
} }
if { $pin == "NULL" } { if { $pin == "NULL" } {
sta_warn_error 130 $warn_error "pin $arg not found." sta_warn_error 130 $warn_error "pin $arg not found."
@ -880,7 +880,7 @@ proc get_port_pin_arg { arg_name arg warn_error } {
proc get_port_pins_error { arg_name arglist } { proc get_port_pins_error { arg_name arglist } {
set pins {} set pins {}
# Copy backslashes that will be removed by foreach. # Copy backslashes that will be removed by foreach.
set arglilst [string map {\\ \\\\} $arglist] set arglist [string map {\\ \\\\} $arglist]
foreach arg $arglist { foreach arg $arglist {
if {[llength $arg] > 1} { if {[llength $arg] > 1} {
# Embedded list. # Embedded list.
@ -891,7 +891,7 @@ proc get_port_pins_error { arg_name arglist } {
lappend pins $arg lappend pins $arg
} elseif { $object_type == "Port" } { } elseif { $object_type == "Port" } {
# Convert port to pin. # Convert port to pin.
lappend pins [find_pin [get_name $arg]] lappend pins [get_port_pin $arg]
} else { } else {
sta_error 131 "$arg_name type '$object_type' is not a pin or port." sta_error 131 "$arg_name type '$object_type' is not a pin or port."
} }

View File

@ -168,6 +168,7 @@ record_public_tests {
report_checks_src_attr report_checks_src_attr
report_json1 report_json1
report_json2 report_json2
slash_port_test
suppress_msg suppress_msg
user_properties user_properties
vcd_begin_end_time vcd_begin_end_time

51
test/slash_port_test.ok Normal file
View File

@ -0,0 +1,51 @@
get_ports *
a/b
level1/Y
level1/level2/level3
out
all_inputs
a/b
level1/Y
level1/level2/level3
all_outputs
out
get_pins *
a/A
a/Y
level1/A
level1/Y
u3/A
u3/B
u3/Y
u4/A
u4/Y
get_cells *
a
level1
u3
u4
get_nets *
a/b
and_out
buf_out
buf_out2
level1/Y
level1/level2/level3
out
get_ports * -filter direction==input
a/b
level1/Y
level1/level2/level3
get_ports * -filter direction==output
out
set_input_delay -clock clk 0 [all_inputs]
set_input_delay -clock clk 0 <Port 'level1/level2/level3'>
set_input_delay -clock clk 0 <Port 'a/b'>
set_input_delay -clock clk 0 <Port 'level1/Y'>
set_false_path -from [all_inputs] -to [all_outputs]
set_data_check -from <Port 'level1/level2/level3'> -to <Port 'a/b'> 0
set_case_analysis 0 <Port 'level1/level2/level3'>
set_case_analysis 0 <Port 'a/b'>
set_case_analysis 0 <Port 'level1/Y'>
report_checks
No paths found.

62
test/slash_port_test.tcl Normal file
View File

@ -0,0 +1,62 @@
# Test: ports with escaped names containing slashes
# Exercises Port-to-Pin conversion paths with escaped Verilog identifiers
# like \level1/level2/level3 that contain hierarchy separators
read_liberty asap7_small.lib.gz
read_verilog slash_port_test.v
link_design slash_port_test
create_clock -name clk -period 500 [get_ports out]
puts {get_ports *}
report_object_full_names [get_ports *]
puts {all_inputs}
report_object_full_names [all_inputs]
puts {all_outputs}
report_object_full_names [all_outputs]
puts {get_pins *}
report_object_full_names [get_pins *]
puts {get_cells *}
report_object_full_names [get_cells *]
puts {get_nets *}
report_object_full_names [get_nets *]
puts {get_ports * -filter direction==input}
report_object_full_names [get_ports * -filter {direction == input}]
puts {get_ports * -filter direction==output}
report_object_full_names [get_ports * -filter {direction == output}]
# get_port_pins_error: Port objects via set_input_delay [all_inputs]
puts {set_input_delay -clock clk 0 [all_inputs]}
set_input_delay -clock clk 0 [all_inputs]
# get_port_pins_error: individual Port objects
foreach port [all_inputs] {
puts "set_input_delay -clock clk 0 <Port '[get_name $port]'>"
set_input_delay -clock clk 0 $port
}
# parse_clk_inst_port_pin_arg: Port objects via set_false_path
puts {set_false_path -from [all_inputs] -to [all_outputs]}
set_false_path -from [all_inputs] -to [all_outputs]
# get_port_pin_error (singular): set_data_check with Port objects
set input_ports [all_inputs]
set from_port [lindex $input_ports 0]
set to_port [lindex $input_ports 1]
puts "set_data_check -from <Port '[get_name $from_port]'> -to <Port '[get_name $to_port]'> 0"
set_data_check -from $from_port -to $to_port 0
# get_port_pin_error (singular): set_case_analysis with Port objects
foreach port [all_inputs] {
puts "set_case_analysis 0 <Port '[get_name $port]'>"
set_case_analysis 0 $port
}
puts {report_checks}
report_checks

20
test/slash_port_test.v Normal file
View File

@ -0,0 +1,20 @@
module slash_port_test (
\level1/level2/level3 ,
\a/b ,
\level1/Y ,
out
);
input \level1/level2/level3 ;
input \a/b ;
input \level1/Y ;
output out;
wire buf_out, buf_out2, and_out;
// Instance named "level1" collides with the prefix of port \level1/level2/level3
BUFx2_ASAP7_75t_R level1 (.A(\level1/level2/level3 ), .Y(buf_out));
// Instance named "a" collides with the prefix of port \a/b
BUFx2_ASAP7_75t_R a (.A(\a/b ), .Y(buf_out2));
AND2x2_ASAP7_75t_R u3 (.A(buf_out), .B(buf_out2), .Y(and_out));
BUFx2_ASAP7_75t_R u4 (.A(and_out), .Y(out));
endmodule