get_* -filter allow true/false, '.' in glob pattern resolves #416

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-04-04 16:19:41 -07:00
parent d6e826ef8b
commit 548b665412
12 changed files with 118 additions and 128 deletions

View File

@ -40,67 +40,56 @@ class Report;
PortSeq
filterPorts(std::string_view filter_expression,
PortSeq *objects,
bool bool_props_as_int,
Sta *sta);
InstanceSeq
filterInstances(std::string_view filter_expression,
InstanceSeq *objects,
bool bool_props_as_int,
Sta *sta);
PinSeq
filterPins(std::string_view filter_expression,
PinSeq *objects,
bool bool_props_as_int,
Sta *sta);
NetSeq
filterNets(std::string_view filter_expression,
NetSeq *objects,
bool bool_props_as_int,
Sta *sta);
ClockSeq
filterClocks(std::string_view filter_expression,
ClockSeq *objects,
bool bool_props_as_int,
Sta *sta);
LibertyCellSeq
filterLibCells(std::string_view filter_expression,
LibertyCellSeq *objects,
bool bool_props_as_int,
Sta *sta);
LibertyPortSeq
filterLibPins(std::string_view filter_expression,
LibertyPortSeq *objects,
bool bool_props_as_int,
Sta *sta);
LibertyLibrarySeq
filterLibertyLibraries(std::string_view filter_expression,
LibertyLibrarySeq *objects,
bool bool_props_as_int,
Sta *sta);
EdgeSeq
filterTimingArcs(std::string_view filter_expression,
EdgeSeq *objects,
bool bool_props_as_int,
Sta *sta);
PathEndSeq
filterPathEnds(std::string_view filter_expression,
PathEndSeq *objects,
bool bool_props_as_int,
Sta *sta);
// For FilterExpr unit tests.
StringSeq
filterExprToPostfix(std::string_view expr,
bool bool_props_as_int,
Report *report);
} // namespace

View File

@ -73,9 +73,9 @@ public:
FilterExpr(std::string_view expression,
Report *report);
std::vector<std::unique_ptr<Token>> postfix(bool bool_props_as_int);
std::vector<std::unique_ptr<Token>> postfix();
private:
std::vector<std::unique_ptr<Token>> lex(bool bool_props_as_int);
std::vector<std::unique_ptr<Token>> lex();
std::vector<std::unique_ptr<Token>> shuntingYard(std::vector<std::unique_ptr<Token>> &infix);
std::string raw_;
@ -106,20 +106,21 @@ FilterExpr::FilterExpr(std::string_view expression,
}
std::vector<std::unique_ptr<FilterExpr::Token>>
FilterExpr::postfix(bool bool_props_as_int)
FilterExpr::postfix()
{
auto infix = lex(bool_props_as_int);
auto infix = lex();
return shuntingYard(infix);
}
std::vector<std::unique_ptr<FilterExpr::Token>>
FilterExpr::lex(bool bool_props_as_int)
FilterExpr::lex()
{
std::vector<std::pair<std::regex, Token::Kind>> token_regexes = {
{std::regex("^\\s+"), Token::Kind::skip},
{std::regex("^defined\\(([a-zA-Z_]+)\\)"), Token::Kind::defined},
{std::regex("^undefined\\(([a-zA-Z_]+)\\)"), Token::Kind::undefined},
{std::regex("^@?([a-zA-Z_]+) *((==|!=|=~|!~) *([0-9a-zA-Z_\\/$\\[\\]*?]+))?"), Token::Kind::predicate},
{std::regex("^@?([a-zA-Z_]+) *((==|!=|=~|!~) *([0-9a-zA-Z_\\/$\\[\\]*?.]+))?"),
Token::Kind::predicate},
{std::regex("^(&&)"), Token::Kind::op_and},
{std::regex("^(\\|\\|)"), Token::Kind::op_or},
{std::regex("^(!)"), Token::Kind::op_inv},
@ -139,9 +140,9 @@ FilterExpr::lex(bool bool_props_as_int)
std::string property = token_match[1].str();
// The default operation on a predicate if an op and arg are
// omitted is 'arg == 1' / 'arg == true'.
// omitted is 'prop == 1 || true'.
std::string op = "==";
std::string arg = (bool_props_as_int ? "1" : "true");
std::string arg = "1";
if (token_match[2].length() != 0) {
op = token_match[3].str();
@ -250,13 +251,18 @@ filterObjects(const char *property,
bool not_pattern_match = stringEq(op, "!~");
for (T *object : all) {
PropertyValue value = properties.getProperty(object, property);
std::string prop_str = value.to_string(network);
const char *prop = prop_str.c_str();
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))
|| (not_pattern_match && !patternMatch(pattern, prop))))
std::string prop = value.to_string(network);
if (value.type() == PropertyValue::Type::bool_) {
// Canonicalize bool true/false to 1/0.
if (stringEqual(pattern, "true"))
pattern = "1";
else if (stringEqual(pattern, "false"))
pattern = "0";
}
if ((exact_match && stringEq(prop.c_str(), pattern))
|| (not_match && !stringEq(prop.c_str(), pattern))
|| (pattern_match && patternMatch(pattern, prop))
|| (not_pattern_match && !patternMatch(pattern, prop)))
filtered_objects.insert(object);
}
return filtered_objects;
@ -265,7 +271,6 @@ filterObjects(const char *property,
template <typename T> std::vector<T*>
filterObjects(std::string_view filter_expression,
std::vector<T*> *objects,
bool bool_props_as_int,
Sta *sta)
{
Report *report = sta->report();
@ -278,7 +283,7 @@ filterObjects(std::string_view filter_expression,
all.insert(object);
FilterExpr filter(filter_expression, report);
auto postfix = filter.postfix(bool_props_as_int);
auto postfix = filter.postfix();
std::stack<std::set<T*>> eval_stack;
for (auto &token : postfix) {
if (token->kind == FilterExpr::Token::Kind::op_or) {
@ -405,100 +410,89 @@ filterObjects(std::string_view filter_expression,
PortSeq
filterPorts(std::string_view filter_expression,
PortSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<const Port>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<const Port>(filter_expression, objects, sta);
}
InstanceSeq
filterInstances(std::string_view filter_expression,
InstanceSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<const Instance>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<const Instance>(filter_expression, objects, sta);
}
PinSeq
filterPins(std::string_view filter_expression,
PinSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<const Pin>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<const Pin>(filter_expression, objects, sta);
}
NetSeq
filterNets(std::string_view filter_expression,
NetSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<const Net>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<const Net>(filter_expression, objects, sta);
}
ClockSeq
filterClocks(std::string_view filter_expression,
ClockSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<Clock>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<Clock>(filter_expression, objects, sta);
}
LibertyCellSeq
filterLibCells(std::string_view filter_expression,
LibertyCellSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<LibertyCell>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<LibertyCell>(filter_expression, objects, sta);
}
LibertyPortSeq
filterLibPins(std::string_view filter_expression,
LibertyPortSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<LibertyPort>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<LibertyPort>(filter_expression, objects, sta);
}
LibertyLibrarySeq
filterLibertyLibraries(std::string_view filter_expression,
LibertyLibrarySeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<LibertyLibrary>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<LibertyLibrary>(filter_expression, objects, sta);
}
EdgeSeq
filterTimingArcs(std::string_view filter_expression,
EdgeSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<Edge>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<Edge>(filter_expression, objects, sta);
}
PathEndSeq
filterPathEnds(std::string_view filter_expression,
PathEndSeq *objects,
bool bool_props_as_int,
Sta *sta)
{
return filterObjects<PathEnd>(filter_expression, objects, bool_props_as_int, sta);
return filterObjects<PathEnd>(filter_expression, objects, sta);
}
StringSeq
filterExprToPostfix(std::string_view expr,
bool bool_props_as_int,
Report *report)
{
FilterExpr filter(expr, report);
auto postfix = filter.postfix(bool_props_as_int);
auto postfix = filter.postfix();
StringSeq result;
for (auto &token : postfix)
result.push_back(token->text);

View File

@ -1493,101 +1493,90 @@ find_register_output_pins(ClockSet *clks,
PortSeq
filter_ports(const char *filter_expression,
PortSeq *ports,
bool bool_props_as_int)
PortSeq *ports)
{
sta::Sta *sta = Sta::sta();
return filterPorts(filter_expression, ports, bool_props_as_int, sta);
return filterPorts(filter_expression, ports, sta);
}
InstanceSeq
filter_insts(const char *filter_expression,
InstanceSeq *insts,
bool bool_props_as_int)
InstanceSeq *insts)
{
sta::Sta *sta = Sta::sta();
return filterInstances(filter_expression, insts, bool_props_as_int, sta);
return filterInstances(filter_expression, insts, sta);
}
PinSeq
filter_pins(const char *filter_expression,
PinSeq *pins,
bool bool_props_as_int)
PinSeq *pins)
{
sta::Sta *sta = Sta::sta();
return filterPins(filter_expression, pins, bool_props_as_int, sta);
return filterPins(filter_expression, pins, sta);
}
NetSeq
filter_nets(const char *filter_expression,
NetSeq *nets,
bool bool_props_as_int)
NetSeq *nets)
{
sta::Sta *sta = Sta::sta();
return filterNets(filter_expression, nets, bool_props_as_int, sta);
return filterNets(filter_expression, nets, sta);
}
ClockSeq
filter_clocks(const char *filter_expression,
ClockSeq *clocks,
bool bool_props_as_int)
ClockSeq *clocks)
{
sta::Sta *sta = Sta::sta();
return filterClocks(filter_expression, clocks, bool_props_as_int, sta);
return filterClocks(filter_expression, clocks, sta);
}
LibertyCellSeq
filter_lib_cells(const char *filter_expression,
LibertyCellSeq *cells,
bool bool_props_as_int)
LibertyCellSeq *cells)
{
sta::Sta *sta = Sta::sta();
return filterLibCells(filter_expression, cells, bool_props_as_int, sta);
return filterLibCells(filter_expression, cells, sta);
}
LibertyPortSeq
filter_lib_pins(const char *filter_expression,
LibertyPortSeq *pins,
bool bool_props_as_int)
LibertyPortSeq *pins)
{
sta::Sta *sta = Sta::sta();
return filterLibPins(filter_expression, pins, bool_props_as_int, sta);
return filterLibPins(filter_expression, pins, sta);
}
LibertyLibrarySeq
filter_liberty_libraries(const char *filter_expression,
LibertyLibrarySeq *libs,
bool bool_props_as_int)
LibertyLibrarySeq *libs)
{
sta::Sta *sta = Sta::sta();
return filterLibertyLibraries(filter_expression, libs, bool_props_as_int, sta);
return filterLibertyLibraries(filter_expression, libs, sta);
}
EdgeSeq
filter_timing_arcs(const char *filter_expression,
EdgeSeq *edges,
bool bool_props_as_int)
EdgeSeq *edges)
{
sta::Sta *sta = Sta::sta();
return filterTimingArcs(filter_expression, edges, bool_props_as_int, sta);
return filterTimingArcs(filter_expression, edges, sta);
}
PathEndSeq
filter_path_ends(const char *filter_expression,
PathEndSeq *path_ends,
bool bool_props_as_int)
PathEndSeq *path_ends)
{
sta::Sta *sta = Sta::sta();
return filterPathEnds(filter_expression, path_ends, bool_props_as_int, sta);
return filterPathEnds(filter_expression, path_ends, sta);
}
// For FilterExpr unit tests.
StringSeq
filter_expr_to_postfix(const char* expr,
bool bool_props_as_int)
filter_expr_to_postfix(const char* expr)
{
Report *report = Sta::sta()->report();
return filterExprToPostfix(expr, bool_props_as_int, report);
return filterExprToPostfix(expr, report);
}
////////////////////////////////////////////////////////////////

View File

@ -393,7 +393,7 @@ proc get_cells { args } {
}
}
if [info exists keys(-filter)] {
set insts [filter_insts $keys(-filter) $insts 1]
set insts [filter_insts $keys(-filter) $insts]
}
return $insts
}
@ -436,7 +436,7 @@ proc get_clocks { args } {
}
}
if [info exists keys(-filter)] {
set clocks [filter_clocks $keys(-filter) $clocks 1]
set clocks [filter_clocks $keys(-filter) $clocks]
}
return $clocks
}
@ -517,7 +517,7 @@ proc get_lib_cells { args } {
}
}
if [info exists keys(-filter)] {
set cells [filter_lib_cells $keys(-filter) $cells 1]
set cells [filter_lib_cells $keys(-filter) $cells]
}
return $cells
}
@ -621,7 +621,7 @@ proc get_lib_pins { args } {
}
}
if [info exists keys(-filter)] {
set ports [filter_lib_pins $keys(-filter) $ports 1]
set ports [filter_lib_pins $keys(-filter) $ports]
}
return $ports
}
@ -671,7 +671,7 @@ proc get_libs { args } {
}
}
if [info exists keys(-filter)] {
set libs [filter_liberty_libraries $keys(-filter) $libs 1]
set libs [filter_liberty_libraries $keys(-filter) $libs]
}
return $libs
}
@ -772,7 +772,7 @@ proc get_nets { args } {
}
}
if [info exists keys(-filter)] {
set nets [filter_nets $keys(-filter) $nets 1]
set nets [filter_nets $keys(-filter) $nets]
}
return $nets
}
@ -863,7 +863,7 @@ proc get_pins { args } {
}
}
if [info exists keys(-filter)] {
set pins [filter_pins $keys(-filter) $pins 1]
set pins [filter_pins $keys(-filter) $pins]
}
return $pins
}
@ -919,7 +919,7 @@ proc get_ports { args } {
}
}
if [info exists keys(-filter)] {
set ports [filter_ports $keys(-filter) $ports 1]
set ports [filter_ports $keys(-filter) $ports]
}
return $ports
}

View File

@ -564,7 +564,7 @@ PropertyValue::to_string(const Network *network) const
case Type::float_:
return unit_->asString(float_, 6);
case Type::bool_:
// true/false would be better but these are TCL true/false values.
// These are TCL true/false values.
if (bool_)
return "1";
else

View File

@ -300,7 +300,7 @@ proc get_timing_edges_cmd { cmd cmd_args } {
cmd_usage_error $cmd
}
if [info exists keys(-filter)] {
set arcs [filter_timing_arcs $keys(-filter) $arcs 1]
set arcs [filter_timing_arcs $keys(-filter) $arcs]
}
return $arcs
}

Binary file not shown.

View File

@ -1,24 +1,11 @@
[get_cells -filter liberty_cell==BUFx2_ASAP7_75t_R *]
u1
[get_clocks -filter is_virtual==0 *]
clk
[get_clocks -filter is_virtual==1 *]
vclk
[get_clocks -filter is_virtual *]
vclk
[get_clocks -filter is_virtual&&is_generated *]
[get_clocks -filter is_virtual&&is_generated==0 *]
vclk
[get_clocks -filter is_virtual||is_generated *]
vclk
[get_clocks -filter is_virtual==0||is_generated *]
clk
[get_lib_cells -filter is_buffer==1 *]
[get_lib_cells -filter is_buffer *]
asap7_small/BUFx2_ASAP7_75t_R
[get_lib_cells -filter is_inverter==0 *]
asap7_small/AND2x2_ASAP7_75t_R
asap7_small/BUFx2_ASAP7_75t_R
asap7_small/DFFHQx4_ASAP7_75t_R
[get_lib_cells -filter is_inverter *]
asap7_small/INVx2_ASAP7_75t_R
[get_lib_pins -filter direction==input BUFx2_ASAP7_75t_R/*]
A
[get_lib_pins -filter direction==output BUFx2_ASAP7_75t_R/*]
@ -54,9 +41,22 @@ in2
out
[get_cells -filter {name ~= *r1*} *]
Error: 2600 -filter parsing failed at '~= *r1*'.
direction == input && name =~ clk*
clk1
clk2
clk3
(direction == input) && (name =~ clk*)"
clk1
clk2
clk3
[get_clocks -filter is_virtual||is_generated *]
vclk
[get_clocks -filter is_virtual==0 *]
clk
[get_clocks -filter is_virtual==false *]
clk
[get_clocks -filter is_virtual==1 *]
vclk
[get_clocks -filter is_virtual==true *]
vclk
{direction == input} {name =~ clk*} {is_clock == 1} && &&

View File

@ -5,29 +5,16 @@ link_design top
create_clock -name clk -period 500 {clk1 clk2 clk3}
create_clock -name vclk -period 1000
# Test filters for each SDC get_* command.
puts {[get_cells -filter liberty_cell==BUFx2_ASAP7_75t_R *]}
report_object_full_names [get_cells -filter liberty_cell==BUFx2_ASAP7_75t_R *]
puts {[get_clocks -filter is_virtual==0 *]}
report_object_full_names [get_clocks -filter is_virtual==0 *]
puts {[get_clocks -filter is_virtual==1 *]}
report_object_full_names [get_clocks -filter is_virtual==1 *]
puts {[get_clocks -filter is_virtual *]}
report_object_full_names [get_clocks -filter is_virtual *]
puts {[get_clocks -filter is_virtual&&is_generated *]}
report_object_full_names [get_clocks -filter is_virtual&&is_generated *]
puts {[get_clocks -filter is_virtual&&is_generated==0 *]}
report_object_full_names [get_clocks -filter is_virtual&&is_generated==0 *]
puts {[get_clocks -filter is_virtual||is_generated *]}
report_object_full_names [get_clocks -filter is_virtual||is_generated *]
puts {[get_clocks -filter is_virtual==0||is_generated *]}
report_object_full_names [get_clocks -filter is_virtual==0||is_generated *]
puts {[get_lib_cells -filter is_buffer==1 *]}
report_object_full_names [get_lib_cells -filter is_buffer==1 *]
puts {[get_lib_cells -filter is_inverter==0 *]}
report_object_full_names [get_lib_cells -filter is_inverter==0 *]
puts {[get_lib_cells -filter is_buffer *]}
report_object_full_names [get_lib_cells -filter is_buffer *]
puts {[get_lib_cells -filter is_inverter *]}
report_object_full_names [get_lib_cells -filter is_inverter *]
puts {[get_lib_pins -filter direction==input BUFx2_ASAP7_75t_R/*]}
report_object_full_names [get_lib_pins -filter direction==input BUFx2_ASAP7_75t_R/*]
@ -55,9 +42,32 @@ puts {[get_cells -filter {name ~= *r1*} *]}
catch {get_cells -filter {name ~= *r1*} *} result
puts $result
# AND pattern match expr
# AND expr
puts {direction == input && name =~ clk*}
report_object_names [get_ports -filter "direction == input && name =~ clk*" *]
# parens around sub-exprs
puts {(direction == input) && (name =~ clk*)"}
report_object_names [get_ports -filter "(direction == input) && (name =~ clk*)" *]
sta::filter_expr_to_postfix "direction == input && name =~ clk* && is_clock" 1
# OR expr
puts {[get_clocks -filter is_virtual||is_generated *]}
report_object_full_names [get_clocks -filter is_virtual||is_generated *]
# unary==0 / unary==false
puts {[get_clocks -filter is_virtual==0 *]}
report_object_full_names [get_clocks -filter is_virtual==0 *]
puts {[get_clocks -filter is_virtual==false *]}
report_object_full_names [get_clocks -filter is_virtual==false *]
# unary==1 / unary==true
puts {[get_clocks -filter is_virtual==1 *]}
report_object_full_names [get_clocks -filter is_virtual==1 *]
puts {[get_clocks -filter is_virtual==true *]}
report_object_full_names [get_clocks -filter is_virtual==true *]
# glob pattern with . (literal dot, no match symantics)
report_object_full_names [get_cells -filter {name =~ .1} *]
puts [sta::filter_expr_to_postfix "direction == input && name =~ clk* && is_clock"]

View File

@ -5,6 +5,7 @@ Y
[get_lib_pins -of_objects [get_lib_cells *]]
A
A
A
B
CLK
D
@ -13,3 +14,4 @@ IQN
Q
Y
Y
Y

View File

@ -11,9 +11,11 @@ vclk
asap7_small/AND2x2_ASAP7_75t_R
asap7_small/BUFx2_ASAP7_75t_R
asap7_small/DFFHQx4_ASAP7_75t_R
asap7_small/INVx2_ASAP7_75t_R
[get_lib_pins]
A
A
A
B
CLK
D
@ -22,6 +24,7 @@ IQN
Q
Y
Y
Y
[get_libs]
asap7_small
[get_nets]

View File

@ -9,9 +9,11 @@ vclk
asap7_small/AND2x2_ASAP7_75t_R
asap7_small/BUFx2_ASAP7_75t_R
asap7_small/DFFHQx4_ASAP7_75t_R
asap7_small/INVx2_ASAP7_75t_R
[get_lib_pins [get_lib_pins]]
A
A
A
B
CLK
D
@ -20,6 +22,7 @@ IQN
Q
Y
Y
Y
[get_libs [get_libs]]
asap7_small
[get_nets [get_nets]]