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
3 changes: 3 additions & 0 deletions include/sta/Sta.hh
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,9 @@ public:
// TCL variable sta_enable_collections
bool enableCollections() const;
void setEnableCollections(bool enable);
// TCL variable sta_case_insensitive_matching.
bool caseInsensitiveMatching() const;
void setCaseInsensitiveMatching(bool enable);
////////////////////////////////////////////////////////////////

Properties &properties() { return properties_; }
Expand Down
6 changes: 6 additions & 0 deletions include/sta/Variables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ public:
// TCL variable sta_enable_collections
bool enableCollections() const { return enable_collections_; }
void setEnableCollections(bool enable) { enable_collections_ = enable; }
// TCL variable sta_case_insensitive_matching.
// Match port/instance/net/cell/clock names ignoring case in the
// get_* and find_*_matching commands.
bool caseInsensitiveMatching() const { return case_insensitive_matching_; }
void setCaseInsensitiveMatching(bool enable) { case_insensitive_matching_ = enable; }


private:
Expand All @@ -127,6 +132,7 @@ private:
bool no_inv_power_calc_{false};
bool strip_escaped_bus_{false};
bool enable_collections_{false};
bool case_insensitive_matching_{false};
};

} // namespace sta
11 changes: 7 additions & 4 deletions sdc/FilterObjects.cc
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ filterObjects(std::string_view property,
bool pattern_match = (op == "=~");
bool not_match = (op == "!=");
bool not_pattern_match = (op == "!~");
// Honor the global sta_case_insensitive_matching variable.
bool nocase = sta->caseInsensitiveMatching();
for (T *object : all) {
PropertyValue value = properties.getProperty(object, property);
std::string prop = value.to_string(network);
Expand All @@ -297,10 +299,11 @@ filterObjects(std::string_view property,
}
}
}
if ((exact_match && prop == pattern)
|| (not_match && prop != pattern)
|| (pattern_match && patternMatch(pattern, prop))
|| (not_pattern_match && !patternMatch(pattern, prop)))
bool eq = nocase ? stringEqual(prop, pattern) : (prop == pattern);
if ((exact_match && eq)
|| (not_match && !eq)
|| (pattern_match && patternMatchNoCase(pattern, prop, nocase))
|| (not_pattern_match && !patternMatchNoCase(pattern, prop, nocase)))
filtered_objects.insert(object);
}
return filtered_objects;
Expand Down
7 changes: 6 additions & 1 deletion sdc/Sdc.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,10 @@ proc get_libs { args } {
}

proc find_liberty_libraries_matching { pattern regexp nocase } {
# Honor the global sta_case_insensitive_matching variable.
if { [case_insensitive_matching] } {
set nocase 1
}
# Remove "lib.db:" reference from the library name.
set ix [string last ".db:" $pattern]
if { $ix != -1 } {
Expand All @@ -735,7 +739,8 @@ proc find_liberty_libraries_matching { pattern regexp nocase } {
while { [$lib_iter has_next] } {
set lib [$lib_iter next]
set lib_name [get_name $lib]
if { (!$regexp && [string match $pattern2 $lib_name]) \
if { (!$regexp && !$nocase && [string match $pattern2 $lib_name]) \
|| (!$regexp && $nocase && [string match -nocase $pattern2 $lib_name]) \
|| ($regexp && $nocase && [regexp -nocase $pattern2 $lib_name]) \
|| ($regexp && !$nocase && [regexp $pattern2 $lib_name]) } {
lappend matches $lib
Expand Down
8 changes: 8 additions & 0 deletions sdc/Variables.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ proc trace_enable_collections { name1 name2 op } {
enable_collections set_enable_collections
}

trace add variable ::sta_case_insensitive_matching {read write} \
sta::trace_case_insensitive_matching

proc trace_case_insensitive_matching { name1 name2 op } {
trace_boolean_var $op ::sta_case_insensitive_matching \
case_insensitive_matching set_case_insensitive_matching
}

trace add variable ::sta_pocv_quantile {read write} \
sta::trace_pocv_quantile

Expand Down
12 changes: 12 additions & 0 deletions search/Search.i
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,18 @@ set_enable_collections(bool enable)
Sta::sta()->setEnableCollections(enable);
}

bool
case_insensitive_matching()
{
return Sta::sta()->caseInsensitiveMatching();
}

void
set_case_insensitive_matching(bool enable)
{
Sta::sta()->setCaseInsensitiveMatching(enable);
}

%} // inline

////////////////////////////////////////////////////////////////
Expand Down
12 changes: 12 additions & 0 deletions search/Sta.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2639,6 +2639,18 @@ Sta::setEnableCollections(bool enable)
variables_->setEnableCollections(enable);
}

bool
Sta::caseInsensitiveMatching() const
{
return variables_->caseInsensitiveMatching();
}

void
Sta::setCaseInsensitiveMatching(bool enable)
{
variables_->setCaseInsensitiveMatching(enable);
}

////////////////////////////////////////////////////////////////

// Init one scene named "default".
Expand Down
31 changes: 31 additions & 0 deletions test/case_insensitive_matching.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
######## sta_case_insensitive_matching = 0 (default) ########
get_ports clk1 = {clk1}
get_ports CLK1 = {}
get_ports CLK* = {}
get_cells R1 = {}
get_pins R1/CK = {}
get_nets R1Q = {}
get_clocks CORE_CLK = {}
get_libs NANGATE* = {}

######## sta_case_insensitive_matching = 1 ########
get_ports CLK1 = {clk1}
get_ports CLK* = {clk1 clk2 clk3}
get_ports In2 = {in2}
get_cells R1 = {r1}
get_cells U* = {u1 u2}
get_pins R1/CK = {r1/CK}
get_pins U1/* = {u1/A u1/Z}
get_nets R1Q = {r1q}
get_clocks CORE_CLK = {core_clk}
get_clocks CORE_* = {core_clk}
get_lib_cells */dff_x1 = {NangateOpenCellLibrary/DFF_X1}
get_lib_pins */dff_x1/ck = {CK}
get_cells -filter =~U* = {u1 u2}
get_cells -filter ==R1 = {r1}
get_libs NANGATE* = {NangateOpenCellLibrary}

######## sta_case_insensitive_matching = 0 (restored) ########
get_ports CLK1 = {}
get_ports clk1 = {clk1}
get_cells -filter ==R1 = {}
61 changes: 61 additions & 0 deletions test/case_insensitive_matching.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Test the sta_case_insensitive_matching variable.
# The design uses lower case object names (ports clk1/in1, instances r1/u1,
# nets r1q, ...) so upper case patterns only match when the variable is on.
read_liberty ../examples/nangate45_typ.lib.gz
read_verilog ../examples/example1.v
link_design top
create_clock -name core_clk -period 1 {clk1 clk2 clk3}

# Print the sorted full names matched by a get_* command.
proc show { label cmd } {
set names {}
foreach_in_collection obj [eval $cmd] {
lappend names [get_full_name $obj]
}
puts "$label = {[lsort $names]}"
}

# Print the sorted names of matched liberty libraries.
proc show_libs { label cmd } {
set names {}
foreach_in_collection lib [eval $cmd] {
lappend names [get_name $lib]
}
puts "$label = {[lsort $names]}"
}

puts "######## sta_case_insensitive_matching = 0 (default) ########"
show "get_ports clk1 " {get_ports -quiet clk1}
show "get_ports CLK1 " {get_ports -quiet CLK1}
show "get_ports CLK* " {get_ports -quiet CLK*}
show "get_cells R1 " {get_cells -quiet R1}
show "get_pins R1/CK " {get_pins -quiet R1/CK}
show "get_nets R1Q " {get_nets -quiet R1Q}
show "get_clocks CORE_CLK " {get_clocks -quiet CORE_CLK}
show_libs "get_libs NANGATE* " {get_libs -quiet NANGATE*}

puts ""
puts "######## sta_case_insensitive_matching = 1 ########"
set sta_case_insensitive_matching 1
show "get_ports CLK1 " {get_ports -quiet CLK1}
show "get_ports CLK* " {get_ports -quiet CLK*}
show "get_ports In2 " {get_ports -quiet In2}
show "get_cells R1 " {get_cells -quiet R1}
show "get_cells U* " {get_cells -quiet U*}
show "get_pins R1/CK " {get_pins -quiet R1/CK}
show "get_pins U1/* " {get_pins -quiet U1/*}
show "get_nets R1Q " {get_nets -quiet R1Q}
show "get_clocks CORE_CLK " {get_clocks -quiet CORE_CLK}
show "get_clocks CORE_* " {get_clocks -quiet CORE_*}
show "get_lib_cells */dff_x1" {get_lib_cells -quiet */dff_x1}
show "get_lib_pins */dff_x1/ck" {get_lib_pins -quiet */dff_x1/ck}
show "get_cells -filter =~U*" {get_cells -quiet -filter "full_name=~U*"}
show "get_cells -filter ==R1" {get_cells -quiet -filter "full_name==R1"}
show_libs "get_libs NANGATE* " {get_libs -quiet NANGATE*}

puts ""
puts "######## sta_case_insensitive_matching = 0 (restored) ########"
set sta_case_insensitive_matching 0
show "get_ports CLK1 " {get_ports -quiet CLK1}
show "get_ports clk1 " {get_ports -quiet clk1}
show "get_cells -filter ==R1" {get_cells -quiet -filter "full_name==R1"}
1 change: 1 addition & 0 deletions test/regression_vars.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ record_example_tests {
}

record_public_tests {
case_insensitive_matching
collections
delay_calc_no_inv
disable_clock_gating_check
Expand Down
34 changes: 29 additions & 5 deletions util/PatternMatch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,26 @@
#include <tcl.h>

#include "Sta.hh"
#include "Variables.hh"

namespace sta {

static std::string stripEscapedBus(std::string_view str);

// TCL variable sta_case_insensitive_matching.
// When enabled, all glob/regexp name matching done by the get_*/find_*_matching
// commands (ports, instances, nets, cells, clocks, ...) ignores case.
// Read lazily so that toggling the variable takes effect immediately and so
// that PatternMatch objects constructed before Sta exists are safe.
static bool
caseInsensitiveMatching()
{
const Sta *sta = Sta::sta();
return sta
&& sta->variables()
&& sta->variables()->caseInsensitiveMatching();
}

PatternMatch::PatternMatch(std::string_view pattern,
bool is_regexp,
bool nocase,
Expand Down Expand Up @@ -72,7 +87,7 @@ void
PatternMatch::compileRegexp()
{
int flags = TCL_REG_ADVANCED;
if (nocase_)
if (nocase_ || caseInsensitiveMatching())
flags |= TCL_REG_NOCASE;
std::string anchored_pattern;
anchored_pattern += '^';
Expand All @@ -96,6 +111,11 @@ regexpWildcards(std::string_view pattern)
bool
PatternMatch::hasWildcards() const
{
// When case-insensitive matching is enabled the find_*_matching functions
// must iterate and match each candidate name rather than doing an exact
// (case-sensitive) hashed lookup, so report the pattern as having wildcards.
if (caseInsensitiveMatching())
return true;
if (is_regexp_)
return regexpWildcards(pattern_);
else
Expand All @@ -106,13 +126,16 @@ bool
PatternMatch::match(std::string_view str) const
{
if (regexp_) {
// regexp_ was compiled with TCL_REG_NOCASE when case-insensitive
// matching is enabled.
std::string buf(str);
const char *cstr = buf.c_str();
return Tcl_RegExpExec(nullptr, regexp_, cstr, cstr) == 1;
}
return patternMatch(pattern_, str) ||
bool nocase = caseInsensitiveMatching();
return patternMatchNoCase(pattern_, str, nocase) ||
(Sta::sta()->stripEscapedBus() &&
patternMatch(pattern_, stripEscapedBus(str)));;
patternMatchNoCase(pattern_, stripEscapedBus(str), nocase));
}

std::string
Expand Down Expand Up @@ -158,9 +181,10 @@ PatternMatch::matchNoCase(std::string_view str) const
const char *cstr = buf.c_str();
return Tcl_RegExpExec(nullptr, regexp_, cstr, cstr) == 1;
}
return patternMatchNoCase(pattern_, str, nocase_) ||
bool nocase = nocase_ || caseInsensitiveMatching();
return patternMatchNoCase(pattern_, str, nocase) ||
(Sta::sta()->stripEscapedBus() &&
patternMatchNoCase(pattern_, stripEscapedBus(str), nocase_));
patternMatchNoCase(pattern_, stripEscapedBus(str), nocase));
}

////////////////////////////////////////////////////////////////
Expand Down
Loading