clang formatted
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
parent
472ba50e6a
commit
17d2c20743
|
|
@ -152,6 +152,7 @@ set(STA_SOURCE
|
||||||
sdc/DeratingFactors.cc
|
sdc/DeratingFactors.cc
|
||||||
sdc/DisabledPorts.cc
|
sdc/DisabledPorts.cc
|
||||||
sdc/ExceptionPath.cc
|
sdc/ExceptionPath.cc
|
||||||
|
sdc/FilterObjects.cc
|
||||||
sdc/InputDrive.cc
|
sdc/InputDrive.cc
|
||||||
sdc/PinPair.cc
|
sdc/PinPair.cc
|
||||||
sdc/PortDelay.cc
|
sdc/PortDelay.cc
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@
|
||||||
#include "TimingArc.hh"
|
#include "TimingArc.hh"
|
||||||
#include "TableModel.hh"
|
#include "TableModel.hh"
|
||||||
#include "Liberty.hh"
|
#include "Liberty.hh"
|
||||||
#include "Network.hh"
|
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
#include "Parasitics.hh"
|
#include "Parasitics.hh"
|
||||||
#include "ArcDelayCalc.hh"
|
#include "ArcDelayCalc.hh"
|
||||||
|
|
@ -78,11 +77,11 @@ exp2(double x);
|
||||||
class DmpError : public Exception
|
class DmpError : public Exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DmpError(const char *what);
|
DmpError(std::string_view what);
|
||||||
virtual const char *what() const noexcept { return what_; }
|
virtual const char *what() const noexcept { return what_.c_str(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *what_;
|
std::string what_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static double
|
static double
|
||||||
|
|
@ -1275,8 +1274,10 @@ newtonRaphson(const int max_iter,
|
||||||
all_under_x_tol = false;
|
all_under_x_tol = false;
|
||||||
x[i] += p[i];
|
x[i] += p[i];
|
||||||
}
|
}
|
||||||
if (all_under_x_tol)
|
if (all_under_x_tol) {
|
||||||
|
eval();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw DmpError("Newton-Raphson max iterations exceeded");
|
throw DmpError("Newton-Raphson max iterations exceeded");
|
||||||
}
|
}
|
||||||
|
|
@ -1667,10 +1668,10 @@ DmpCeffDelayCalc::copyState(const StaState *sta)
|
||||||
dmp_zero_c2_->copyState(sta);
|
dmp_zero_c2_->copyState(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
DmpError::DmpError(const char *what) :
|
DmpError::DmpError(std::string_view what) :
|
||||||
what_(what)
|
what_(what)
|
||||||
{
|
{
|
||||||
// printf("DmpError %s\n", what);
|
// sta::print(stdout, "DmpError {}\n", what);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This saves about 2.5% in overall run time on designs with SPEF.
|
// This saves about 2.5% in overall run time on designs with SPEF.
|
||||||
|
|
|
||||||
|
|
@ -425,8 +425,9 @@ GraphDelayCalc::seedDrvrSlew(Vertex *drvr_vertex,
|
||||||
if (drvr_cell) {
|
if (drvr_cell) {
|
||||||
if (from_port == nullptr)
|
if (from_port == nullptr)
|
||||||
from_port = driveCellDefaultFromPort(drvr_cell, to_port);
|
from_port = driveCellDefaultFromPort(drvr_cell, to_port);
|
||||||
findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf,
|
findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf, from_port,
|
||||||
from_port, from_slews, to_port, scene, min_max);
|
from_slews, to_port, scene, min_max,
|
||||||
|
arc_delay_calc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
seedNoDrvrCellSlew(drvr_vertex, drvr_pin, rf, drive, scene, min_max,
|
seedNoDrvrCellSlew(drvr_vertex, drvr_pin, rf, drive, scene, min_max,
|
||||||
|
|
@ -601,7 +602,8 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell,
|
||||||
float *from_slews,
|
float *from_slews,
|
||||||
const LibertyPort *to_port,
|
const LibertyPort *to_port,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max,
|
||||||
|
ArcDelayCalc *arc_delay_calc)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "delay_calc", 2, " driver cell {} {}",
|
debugPrint(debug_, "delay_calc", 2, " driver cell {} {}",
|
||||||
drvr_cell->name(),
|
drvr_cell->name(),
|
||||||
|
|
@ -610,11 +612,11 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell,
|
||||||
for (TimingArc *arc : arc_set->arcs()) {
|
for (TimingArc *arc : arc_set->arcs()) {
|
||||||
if (arc->toEdge()->asRiseFall() == rf) {
|
if (arc->toEdge()->asRiseFall() == rf) {
|
||||||
float from_slew = from_slews[arc->fromEdge()->index()];
|
float from_slew = from_slews[arc->fromEdge()->index()];
|
||||||
findInputArcDelay(drvr_pin, drvr_vertex, arc, from_slew, scene, min_max);
|
findInputArcDelay(drvr_pin, drvr_vertex, arc, from_slew, scene, min_max,
|
||||||
|
arc_delay_calc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arc_delay_calc_->finishDrvrPin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driving cell delay is the load dependent delay, which is the gate
|
// Driving cell delay is the load dependent delay, which is the gate
|
||||||
|
|
@ -626,7 +628,8 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max,
|
||||||
|
ArcDelayCalc *arc_delay_calc)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "delay_calc", 3, " {} {} -> {} {} ({})",
|
debugPrint(debug_, "delay_calc", 3, " {} {} -> {} {} ({})",
|
||||||
arc->from()->name(),
|
arc->from()->name(),
|
||||||
|
|
@ -640,20 +643,18 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
|
|
||||||
const Parasitic *parasitic;
|
const Parasitic *parasitic;
|
||||||
float load_cap;
|
float load_cap;
|
||||||
parasiticLoad(drvr_pin, drvr_rf, scene, min_max, nullptr, arc_delay_calc_,
|
parasiticLoad(drvr_pin, drvr_rf, scene, min_max, nullptr, arc_delay_calc,
|
||||||
load_cap, parasitic);
|
load_cap, parasitic);
|
||||||
|
|
||||||
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
||||||
ArcDcalcResult intrinsic_result =
|
ArcDcalcResult intrinsic_result =
|
||||||
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
|
arc_delay_calc->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
|
||||||
load_pin_index_map, scene, min_max);
|
load_pin_index_map, scene, min_max);
|
||||||
const ArcDelay &intrinsic_delay = intrinsic_result.gateDelay();
|
const ArcDelay &intrinsic_delay = intrinsic_result.gateDelay();
|
||||||
|
|
||||||
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
|
ArcDcalcResult gate_result =
|
||||||
Slew(from_slew), load_cap,
|
arc_delay_calc->gateDelay(drvr_pin, arc, Slew(from_slew), load_cap,
|
||||||
parasitic,
|
parasitic, load_pin_index_map, scene, min_max);
|
||||||
load_pin_index_map,
|
|
||||||
scene, min_max);
|
|
||||||
const ArcDelay &gate_delay = gate_result.gateDelay();
|
const ArcDelay &gate_delay = gate_result.gateDelay();
|
||||||
const Slew &gate_slew = gate_result.drvrSlew();
|
const Slew &gate_slew = gate_result.drvrSlew();
|
||||||
|
|
||||||
|
|
@ -666,7 +667,7 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
|
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
|
||||||
annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map,
|
annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map,
|
||||||
load_delay, false, scene, min_max);
|
load_delay, false, scene, min_max);
|
||||||
arc_delay_calc_->finishDrvrPin();
|
arc_delay_calc->finishDrvrPin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1598,41 +1599,33 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
|
||||||
for (Scene *scene : scenes_) {
|
for (Scene *scene : scenes_) {
|
||||||
for (const MinMax *min_max : MinMax::range()) {
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
||||||
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
|
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
|
||||||
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf,
|
const Slew &from_slew =
|
||||||
scene, min_max);
|
checkEdgeClkSlew(from_vertex, from_rf, scene, min_max);
|
||||||
const Slew to_slew = graph_->slew(to_vertex, to_rf, ap_index);
|
const Slew to_slew = graph_->slew(to_vertex, to_rf, ap_index);
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
debugPrint(debug_, "delay_calc", 3, " {} {} -> {} {} ({}) scene:{}/{}",
|
||||||
" {} {} -> {} {} ({}) scene:{}/{}",
|
arc_set->from()->name(), arc->fromEdge()->to_string(),
|
||||||
arc_set->from()->name(),
|
arc_set->to()->name(), arc->toEdge()->to_string(),
|
||||||
arc->fromEdge()->to_string(),
|
arc_set->role()->to_string(), scene->name(),
|
||||||
arc_set->to()->name(),
|
|
||||||
arc->toEdge()->to_string(),
|
|
||||||
arc_set->role()->to_string(),
|
|
||||||
scene->name(),
|
|
||||||
min_max->to_string());
|
min_max->to_string());
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
debugPrint(debug_, "delay_calc", 3, " from_slew = {} to_slew = {}",
|
||||||
" from_slew = {} to_slew = {}",
|
delayAsString(from_slew, this), delayAsString(to_slew, this));
|
||||||
delayAsString(from_slew, this),
|
float related_out_cap = 0.0;
|
||||||
delayAsString(to_slew, this));
|
if (related_out_pin)
|
||||||
float related_out_cap = 0.0;
|
|
||||||
if (related_out_pin)
|
|
||||||
related_out_cap = loadCap(related_out_pin, to_rf,scene,min_max,
|
related_out_cap = loadCap(related_out_pin, to_rf,scene,min_max,
|
||||||
arc_delay_calc);
|
arc_delay_calc);
|
||||||
ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
|
ArcDelay check_delay = arc_delay_calc->checkDelay(
|
||||||
to_slew, related_out_cap,
|
to_pin, arc, from_slew, to_slew, related_out_cap, scene, min_max);
|
||||||
scene, min_max);
|
debugPrint(debug_, "delay_calc", 3, " check_delay = {}",
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
delayAsString(check_delay, this));
|
||||||
" check_delay = {}",
|
graph_->setArcDelay(edge, arc, ap_index, check_delay);
|
||||||
delayAsString(check_delay, this));
|
delay_changed = true;
|
||||||
graph_->setArcDelay(edge, arc, ap_index, check_delay);
|
arc_delay_calc_->finishDrvrPin();
|
||||||
delay_changed = true;
|
}
|
||||||
arc_delay_calc_->finishDrvrPin();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (delay_changed && observer_)
|
if (delay_changed && observer_)
|
||||||
observer_->checkDelayChangedTo(to_vertex);
|
observer_->checkDelayChangedTo(to_vertex);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
// OpenSTA, Static Timing Analyzer
|
||||||
|
// Copyright (c) 2025, Parallax Software, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software.
|
||||||
|
//
|
||||||
|
// Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "SdcClass.hh"
|
||||||
|
#include "SearchClass.hh"
|
||||||
|
#include "StringUtil.hh"
|
||||||
|
|
||||||
|
namespace sta {
|
||||||
|
|
||||||
|
class Sta;
|
||||||
|
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 sta
|
||||||
|
|
@ -167,24 +167,26 @@ protected:
|
||||||
void seedLoadSlew(Vertex *vertex);
|
void seedLoadSlew(Vertex *vertex);
|
||||||
void setInputPortWireDelays(Vertex *vertex);
|
void setInputPortWireDelays(Vertex *vertex);
|
||||||
void findInputDriverDelay(const LibertyCell *drvr_cell,
|
void findInputDriverDelay(const LibertyCell *drvr_cell,
|
||||||
const Pin *drvr_pin,
|
const Pin *drvr_pin,
|
||||||
Vertex *drvr_vertex,
|
Vertex *drvr_vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const LibertyPort *from_port,
|
const LibertyPort *from_port,
|
||||||
float *from_slews,
|
float *from_slews,
|
||||||
const LibertyPort *to_port,
|
const LibertyPort *to_port,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max,
|
||||||
|
ArcDelayCalc *arc_delay_calc);
|
||||||
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
|
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
|
||||||
const LibertyPort *to_port);
|
const LibertyPort *to_port);
|
||||||
int findPortIndex(const LibertyCell *cell,
|
int findPortIndex(const LibertyCell *cell,
|
||||||
const LibertyPort *port);
|
const LibertyPort *port);
|
||||||
void findInputArcDelay(const Pin *drvr_pin,
|
void findInputArcDelay(const Pin *drvr_pin,
|
||||||
Vertex *drvr_vertex,
|
Vertex *drvr_vertex,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max,
|
||||||
|
ArcDelayCalc *arc_delay_calc);
|
||||||
void findDriverDelays(Vertex *drvr_vertex,
|
void findDriverDelays(Vertex *drvr_vertex,
|
||||||
ArcDelayCalc *arc_delay_calc,
|
ArcDelayCalc *arc_delay_calc,
|
||||||
LoadPinIndexMap &load_pin_index_map);
|
LoadPinIndexMap &load_pin_index_map);
|
||||||
|
|
|
||||||
|
|
@ -108,19 +108,18 @@ GateTableModel::gateDelay(const Pvt *pvt,
|
||||||
float &gate_delay,
|
float &gate_delay,
|
||||||
float &drvr_slew) const
|
float &drvr_slew) const
|
||||||
{
|
{
|
||||||
if (delay_models_)
|
if (delay_models_ && delay_models_->model())
|
||||||
gate_delay = findValue(pvt, delay_models_->model(), in_slew, load_cap, 0.0);
|
gate_delay = findValue(pvt, delay_models_->model(), in_slew, load_cap, 0.0);
|
||||||
else
|
else
|
||||||
gate_delay = 0.0;
|
gate_delay = 0.0;
|
||||||
if (slew_models_)
|
if (slew_models_ && slew_models_->model()) {
|
||||||
drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
|
drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
|
||||||
|
// Clip negative slews to zero.
|
||||||
|
if (drvr_slew < 0.0)
|
||||||
|
drvr_slew = 0.0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
drvr_slew = 0.0;
|
drvr_slew = 0.0;
|
||||||
// TODO: Check for a better solution than clip negative delays and slews to zero.
|
|
||||||
//if (gate_delay < 0.0)
|
|
||||||
// gate_delay = 0.0;
|
|
||||||
if (drvr_slew < 0.0)
|
|
||||||
drvr_slew = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,506 @@
|
||||||
|
// OpenSTA, Static Timing Analyzer
|
||||||
|
// Copyright (c) 2025, Parallax Software, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software.
|
||||||
|
//
|
||||||
|
// Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
#include "FilterObjects.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <stack>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Property.hh"
|
||||||
|
#include "PatternMatch.hh"
|
||||||
|
#include "Sta.hh"
|
||||||
|
|
||||||
|
namespace sta {
|
||||||
|
|
||||||
|
class FilterExpr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
enum class Kind {
|
||||||
|
skip = 0,
|
||||||
|
predicate,
|
||||||
|
op_lparen,
|
||||||
|
op_rparen,
|
||||||
|
op_or,
|
||||||
|
op_and,
|
||||||
|
op_inv,
|
||||||
|
defined,
|
||||||
|
undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
Token(std::string text, Kind kind);
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
Kind kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PredicateToken : public Token
|
||||||
|
{
|
||||||
|
PredicateToken(std::string property, std::string op, std::string arg);
|
||||||
|
|
||||||
|
std::string property;
|
||||||
|
std::string op;
|
||||||
|
std::string arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterExpr(std::string_view expression, Report *report);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Token>> postfix(bool bool_props_as_int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<Token>> lex(bool bool_props_as_int);
|
||||||
|
std::vector<std::unique_ptr<Token>> shuntingYard(
|
||||||
|
std::vector<std::unique_ptr<Token>> &infix);
|
||||||
|
|
||||||
|
std::string raw_;
|
||||||
|
Report *report_;
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterExpr::Token::Token(std::string text, Token::Kind kind) :
|
||||||
|
text(text),
|
||||||
|
kind(kind)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterExpr::PredicateToken::PredicateToken(std::string property,
|
||||||
|
std::string op,
|
||||||
|
std::string arg) :
|
||||||
|
Token(property + " " + op + " " + arg, Token::Kind::predicate),
|
||||||
|
property(property),
|
||||||
|
op(op),
|
||||||
|
arg(arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterExpr::FilterExpr(std::string_view expression, Report *report) :
|
||||||
|
raw_(expression),
|
||||||
|
report_(report)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<FilterExpr::Token>>
|
||||||
|
FilterExpr::postfix(bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
auto infix = lex(bool_props_as_int);
|
||||||
|
return shuntingYard(infix);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<FilterExpr::Token>>
|
||||||
|
FilterExpr::lex(bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
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("^(&&)"), Token::Kind::op_and},
|
||||||
|
{std::regex("^(\\|\\|)"), Token::Kind::op_or},
|
||||||
|
{std::regex("^(!)"), Token::Kind::op_inv},
|
||||||
|
{std::regex("^(\\()"), Token::Kind::op_lparen},
|
||||||
|
{std::regex("^(\\))"), Token::Kind::op_rparen},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Token>> result;
|
||||||
|
const char *ptr = &raw_[0];
|
||||||
|
bool match = false;
|
||||||
|
while (*ptr != '\0') {
|
||||||
|
match = false;
|
||||||
|
for (auto &[regex, kind] : token_regexes) {
|
||||||
|
std::cmatch token_match;
|
||||||
|
if (std::regex_search(ptr, token_match, regex)) {
|
||||||
|
if (kind == Token::Kind::predicate) {
|
||||||
|
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'.
|
||||||
|
std::string op = "==";
|
||||||
|
std::string arg = (bool_props_as_int ? "1" : "true");
|
||||||
|
|
||||||
|
if (token_match[2].length() != 0) {
|
||||||
|
op = token_match[3].str();
|
||||||
|
arg = token_match[4].str();
|
||||||
|
}
|
||||||
|
result.push_back(std::make_unique<PredicateToken>(property, op, arg));
|
||||||
|
}
|
||||||
|
else if (kind == Token::Kind::defined)
|
||||||
|
result.push_back(std::make_unique<Token>(token_match[1].str(), kind));
|
||||||
|
else if (kind == Token::Kind::undefined)
|
||||||
|
result.push_back(std::make_unique<Token>(token_match[1].str(), kind));
|
||||||
|
else if (kind != Token::Kind::skip)
|
||||||
|
result.push_back(
|
||||||
|
std::make_unique<Token>(std::string(ptr, token_match.length()), kind));
|
||||||
|
ptr += token_match.length();
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!match)
|
||||||
|
report_->error(2600, "-filter parsing failed at '{}'.", ptr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<FilterExpr::Token>>
|
||||||
|
FilterExpr::shuntingYard(std::vector<std::unique_ptr<Token>> &infix)
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<Token>> output;
|
||||||
|
std::stack<std::unique_ptr<Token>> operator_stack;
|
||||||
|
|
||||||
|
for (auto &token : infix) {
|
||||||
|
switch (token->kind) {
|
||||||
|
case Token::Kind::predicate:
|
||||||
|
output.push_back(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::op_or:
|
||||||
|
[[fallthrough]];
|
||||||
|
case Token::Kind::op_and:
|
||||||
|
// The operators' enum values are ascending by precedence:
|
||||||
|
// inv > and > or
|
||||||
|
while (operator_stack.size() && operator_stack.top()->kind > token->kind) {
|
||||||
|
output.push_back(std::move(operator_stack.top()));
|
||||||
|
operator_stack.pop();
|
||||||
|
}
|
||||||
|
operator_stack.push(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::op_inv:
|
||||||
|
// Unary with highest precedence, no need for the while loop.
|
||||||
|
operator_stack.push(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::defined:
|
||||||
|
operator_stack.push(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::undefined:
|
||||||
|
operator_stack.push(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::op_lparen:
|
||||||
|
operator_stack.push(std::move(token));
|
||||||
|
break;
|
||||||
|
case Token::Kind::op_rparen:
|
||||||
|
if (operator_stack.empty())
|
||||||
|
report_->error(2601, "-filter extraneous ).");
|
||||||
|
while (operator_stack.size()
|
||||||
|
&& operator_stack.top()->kind != Token::Kind::op_lparen) {
|
||||||
|
output.push_back(std::move(operator_stack.top()));
|
||||||
|
operator_stack.pop();
|
||||||
|
if (operator_stack.empty())
|
||||||
|
report_->error(2602, "-filter extraneous ).");
|
||||||
|
}
|
||||||
|
// Guaranteed to be lparen at this point.
|
||||||
|
operator_stack.pop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unhandled/skip.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (operator_stack.size()) {
|
||||||
|
if (operator_stack.top()->kind == Token::Kind::op_lparen)
|
||||||
|
report_->error(2603, "-filter unmatched (.");
|
||||||
|
output.push_back(std::move(operator_stack.top()));
|
||||||
|
operator_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::set<T *>
|
||||||
|
filterObjects(const char *property,
|
||||||
|
const char *op,
|
||||||
|
const char *pattern,
|
||||||
|
std::set<T *> &all,
|
||||||
|
Sta *sta)
|
||||||
|
{
|
||||||
|
Properties &properties = sta->properties();
|
||||||
|
Network *network = sta->network();
|
||||||
|
auto filtered_objects = std::set<T *>();
|
||||||
|
bool exact_match = stringEq(op, "==");
|
||||||
|
bool pattern_match = stringEq(op, "=~");
|
||||||
|
bool not_match = stringEq(op, "!=");
|
||||||
|
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))))
|
||||||
|
filtered_objects.insert(object);
|
||||||
|
}
|
||||||
|
return filtered_objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
Network *network = sta->network();
|
||||||
|
Properties &properties = sta->properties();
|
||||||
|
std::vector<T *> result;
|
||||||
|
if (objects) {
|
||||||
|
std::set<T *> all;
|
||||||
|
for (auto object : *objects)
|
||||||
|
all.insert(object);
|
||||||
|
|
||||||
|
FilterExpr filter(filter_expression, report);
|
||||||
|
auto postfix = filter.postfix(bool_props_as_int);
|
||||||
|
std::stack<std::set<T *>> eval_stack;
|
||||||
|
for (auto &token : postfix) {
|
||||||
|
if (token->kind == FilterExpr::Token::Kind::op_or) {
|
||||||
|
if (eval_stack.size() < 2)
|
||||||
|
report->error(2604, "-filter logical OR requires at least two operands.");
|
||||||
|
auto arg0 = eval_stack.top();
|
||||||
|
eval_stack.pop();
|
||||||
|
auto arg1 = eval_stack.top();
|
||||||
|
eval_stack.pop();
|
||||||
|
auto union_result = std::set<T *>();
|
||||||
|
std::set_union(arg0.cbegin(), arg0.cend(), arg1.cbegin(), arg1.cend(),
|
||||||
|
std::inserter(union_result, union_result.begin()));
|
||||||
|
eval_stack.push(union_result);
|
||||||
|
}
|
||||||
|
else if (token->kind == FilterExpr::Token::Kind::op_and) {
|
||||||
|
if (eval_stack.size() < 2) {
|
||||||
|
report->error(2605, "-filter logical AND requires two operands.");
|
||||||
|
}
|
||||||
|
auto arg0 = eval_stack.top();
|
||||||
|
eval_stack.pop();
|
||||||
|
auto arg1 = eval_stack.top();
|
||||||
|
eval_stack.pop();
|
||||||
|
auto intersection_result = std::set<T *>();
|
||||||
|
std::set_intersection(
|
||||||
|
arg0.cbegin(), arg0.cend(), arg1.cbegin(), arg1.cend(),
|
||||||
|
std::inserter(intersection_result, intersection_result.begin()));
|
||||||
|
eval_stack.push(intersection_result);
|
||||||
|
}
|
||||||
|
else if (token->kind == FilterExpr::Token::Kind::op_inv) {
|
||||||
|
if (eval_stack.size() < 1) {
|
||||||
|
report->error(2606, "-filter NOT missing operand.");
|
||||||
|
}
|
||||||
|
auto arg0 = eval_stack.top();
|
||||||
|
eval_stack.pop();
|
||||||
|
|
||||||
|
auto difference_result = std::set<T *>();
|
||||||
|
std::set_difference(
|
||||||
|
all.cbegin(), all.cend(), arg0.cbegin(), arg0.cend(),
|
||||||
|
std::inserter(difference_result, difference_result.begin()));
|
||||||
|
eval_stack.push(difference_result);
|
||||||
|
}
|
||||||
|
else if (token->kind == FilterExpr::Token::Kind::defined
|
||||||
|
|| token->kind == FilterExpr::Token::Kind::undefined) {
|
||||||
|
bool should_be_defined = (token->kind == FilterExpr::Token::Kind::defined);
|
||||||
|
auto result = std::set<T *>();
|
||||||
|
for (auto object : all) {
|
||||||
|
PropertyValue value = properties.getProperty(object, token->text);
|
||||||
|
bool is_defined = false;
|
||||||
|
switch (value.type()) {
|
||||||
|
case PropertyValue::Type::float_:
|
||||||
|
is_defined = value.floatValue() != 0;
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::bool_:
|
||||||
|
is_defined = value.boolValue();
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::string:
|
||||||
|
case PropertyValue::Type::liberty_library:
|
||||||
|
case PropertyValue::Type::liberty_cell:
|
||||||
|
case PropertyValue::Type::liberty_port:
|
||||||
|
case PropertyValue::Type::library:
|
||||||
|
case PropertyValue::Type::cell:
|
||||||
|
case PropertyValue::Type::port:
|
||||||
|
case PropertyValue::Type::instance:
|
||||||
|
case PropertyValue::Type::pin:
|
||||||
|
case PropertyValue::Type::net:
|
||||||
|
case PropertyValue::Type::clk:
|
||||||
|
is_defined = value.to_string(network) != "";
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::none:
|
||||||
|
is_defined = false;
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::pins:
|
||||||
|
is_defined = value.pins()->size() > 0;
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::clks:
|
||||||
|
is_defined = value.clocks()->size() > 0;
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::paths:
|
||||||
|
is_defined = value.paths()->size() > 0;
|
||||||
|
break;
|
||||||
|
case PropertyValue::Type::pwr_activity:
|
||||||
|
is_defined = value.pwrActivity().isSet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (is_defined == should_be_defined) {
|
||||||
|
result.insert(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eval_stack.push(result);
|
||||||
|
}
|
||||||
|
else if (token->kind == FilterExpr::Token::Kind::predicate) {
|
||||||
|
auto *predicate_token =
|
||||||
|
static_cast<FilterExpr::PredicateToken *>(token.get());
|
||||||
|
auto result = filterObjects<T>(predicate_token->property.c_str(),
|
||||||
|
predicate_token->op.c_str(),
|
||||||
|
predicate_token->arg.c_str(), all, sta);
|
||||||
|
eval_stack.push(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eval_stack.size() == 0)
|
||||||
|
report->error(2607, "-filter expression is empty.");
|
||||||
|
if (eval_stack.size() > 1)
|
||||||
|
// huh?
|
||||||
|
report->error(2608, "-filter expression evaluated to multiple sets.");
|
||||||
|
auto result_set = eval_stack.top();
|
||||||
|
result.resize(result_set.size());
|
||||||
|
std::copy(result_set.begin(), result_set.end(), result.begin());
|
||||||
|
std::map<T *, int> objects_i;
|
||||||
|
for (size_t i = 0; i < objects->size(); ++i)
|
||||||
|
objects_i[objects->at(i)] = i;
|
||||||
|
std::sort(result.begin(), result.end(),
|
||||||
|
[&](T *a, T *b) { return objects_i[a] < objects_i[b]; });
|
||||||
|
delete objects;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
StringSeq result;
|
||||||
|
for (auto &token : postfix)
|
||||||
|
result.push_back(token->text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sta
|
||||||
170
sdc/Sdc.i
170
sdc/Sdc.i
|
|
@ -34,6 +34,7 @@
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "PortDelay.hh"
|
#include "PortDelay.hh"
|
||||||
#include "Property.hh"
|
#include "Property.hh"
|
||||||
|
#include "FilterObjects.hh"
|
||||||
#include "Sta.hh"
|
#include "Sta.hh"
|
||||||
|
|
||||||
using namespace sta;
|
using namespace sta;
|
||||||
|
|
@ -1490,114 +1491,103 @@ find_register_output_pins(ClockSet *clks,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename T> std::vector<T*>
|
|
||||||
filter_objects(std::string_view property,
|
|
||||||
std::string_view op,
|
|
||||||
std::string_view pattern,
|
|
||||||
std::vector<T*> *objects)
|
|
||||||
{
|
|
||||||
std::vector<T*> filtered_objects;
|
|
||||||
if (objects) {
|
|
||||||
Sta *sta = Sta::sta();
|
|
||||||
Properties &properties = sta->properties();
|
|
||||||
bool exact_match = op == "==";
|
|
||||||
bool pattern_match = op == "=~";
|
|
||||||
bool not_match = op == "!=";
|
|
||||||
bool not_pattern_match = op == "!~";
|
|
||||||
for (T *object : *objects) {
|
|
||||||
PropertyValue value(properties.getProperty(object, property));
|
|
||||||
std::string prop_value = value.to_string(sta->network());
|
|
||||||
if (!prop_value.empty()
|
|
||||||
&& ((exact_match && prop_value == pattern)
|
|
||||||
|| (not_match && prop_value != pattern)
|
|
||||||
|| (pattern_match && patternMatch(pattern, prop_value))
|
|
||||||
|| (not_pattern_match && !patternMatch(pattern, prop_value))))
|
|
||||||
filtered_objects.push_back(object);
|
|
||||||
}
|
|
||||||
delete objects;
|
|
||||||
}
|
|
||||||
return filtered_objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
PortSeq
|
PortSeq
|
||||||
filter_ports(std::string_view property,
|
filter_ports(const char *filter_expression,
|
||||||
std::string_view op,
|
PortSeq *ports,
|
||||||
std::string_view pattern,
|
bool bool_props_as_int)
|
||||||
PortSeq *ports)
|
|
||||||
{
|
{
|
||||||
return filter_objects<const Port>(property, op, pattern, ports);
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterPorts(filter_expression, ports, bool_props_as_int, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceSeq
|
InstanceSeq
|
||||||
filter_insts(std::string_view property,
|
filter_insts(const char *filter_expression,
|
||||||
std::string_view op,
|
InstanceSeq *insts,
|
||||||
std::string_view pattern,
|
bool bool_props_as_int)
|
||||||
InstanceSeq *insts)
|
|
||||||
{
|
{
|
||||||
return filter_objects<const Instance>(property, op, pattern, insts);
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterInstances(filter_expression, insts, bool_props_as_int, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
PinSeq
|
PinSeq
|
||||||
filter_pins(std::string_view property,
|
filter_pins(const char *filter_expression,
|
||||||
std::string_view op,
|
PinSeq *pins,
|
||||||
std::string_view pattern,
|
bool bool_props_as_int)
|
||||||
PinSeq *pins)
|
|
||||||
{
|
{
|
||||||
return filter_objects<const Pin>(property, op, pattern, pins);
|
sta::Sta *sta = Sta::sta();
|
||||||
}
|
return filterPins(filter_expression, pins, bool_props_as_int, sta);
|
||||||
|
|
||||||
ClockSeq
|
|
||||||
filter_clocks(std::string_view property,
|
|
||||||
std::string_view op,
|
|
||||||
std::string_view pattern,
|
|
||||||
ClockSeq *clocks)
|
|
||||||
{
|
|
||||||
return filter_objects<Clock>(property, op, pattern, clocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
LibertyCellSeq
|
|
||||||
filter_lib_cells(std::string_view property,
|
|
||||||
std::string_view op,
|
|
||||||
std::string_view pattern,
|
|
||||||
LibertyCellSeq *cells)
|
|
||||||
{
|
|
||||||
return filter_objects<LibertyCell>(property, op, pattern, cells);
|
|
||||||
}
|
|
||||||
|
|
||||||
LibertyPortSeq
|
|
||||||
filter_lib_pins(std::string_view property,
|
|
||||||
std::string_view op,
|
|
||||||
std::string_view pattern,
|
|
||||||
LibertyPortSeq *pins)
|
|
||||||
{
|
|
||||||
return filter_objects<LibertyPort>(property, op, pattern, pins);
|
|
||||||
}
|
|
||||||
|
|
||||||
LibertyLibrarySeq
|
|
||||||
filter_liberty_libraries(std::string_view property,
|
|
||||||
std::string_view op,
|
|
||||||
std::string_view pattern,
|
|
||||||
LibertyLibrarySeq *libs)
|
|
||||||
{
|
|
||||||
return filter_objects<LibertyLibrary>(property, op, pattern, libs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetSeq
|
NetSeq
|
||||||
filter_nets(std::string_view property,
|
filter_nets(const char *filter_expression,
|
||||||
std::string_view op,
|
NetSeq *nets,
|
||||||
std::string_view pattern,
|
bool bool_props_as_int)
|
||||||
NetSeq *nets)
|
|
||||||
{
|
{
|
||||||
return filter_objects<const Net>(property, op, pattern, nets);
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterNets(filter_expression, nets, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockSeq
|
||||||
|
filter_clocks(const char *filter_expression,
|
||||||
|
ClockSeq *clocks,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterClocks(filter_expression, clocks, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
LibertyCellSeq
|
||||||
|
filter_lib_cells(const char *filter_expression,
|
||||||
|
LibertyCellSeq *cells,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterLibCells(filter_expression, cells, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
LibertyPortSeq
|
||||||
|
filter_lib_pins(const char *filter_expression,
|
||||||
|
LibertyPortSeq *pins,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterLibPins(filter_expression, pins, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
LibertyLibrarySeq
|
||||||
|
filter_liberty_libraries(const char *filter_expression,
|
||||||
|
LibertyLibrarySeq *libs,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterLibertyLibraries(filter_expression, libs, bool_props_as_int, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeSeq
|
EdgeSeq
|
||||||
filter_timing_arcs(std::string_view property,
|
filter_timing_arcs(const char *filter_expression,
|
||||||
std::string_view op,
|
EdgeSeq *edges,
|
||||||
std::string_view pattern,
|
bool bool_props_as_int)
|
||||||
EdgeSeq *edges)
|
|
||||||
{
|
{
|
||||||
return filter_objects<Edge>(property, op, pattern, edges);
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterTimingArcs(filter_expression, edges, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
PathEndSeq
|
||||||
|
filter_path_ends(const char *filter_expression,
|
||||||
|
PathEndSeq *path_ends,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterPathEnds(filter_expression, path_ends, bool_props_as_int, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For FilterExpr unit tests.
|
||||||
|
StringSeq
|
||||||
|
filter_expr_to_postfix(const char* expr,
|
||||||
|
bool bool_props_as_int)
|
||||||
|
{
|
||||||
|
Report *report = Sta::sta()->report();
|
||||||
|
return filterExprToPostfix(expr, bool_props_as_int, report);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
52
sdc/Sdc.tcl
52
sdc/Sdc.tcl
|
|
@ -315,42 +315,6 @@ proc current_design { {design ""} } {
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
# Generic get_* filter.
|
|
||||||
proc filter_objs { filter objects filter_function object_type } {
|
|
||||||
# Regexp for attr op arg (e.g., full_name =~ *blk*)
|
|
||||||
set filter_regexp_op {@?([a-zA-Z_]+) *(==|!=|=~|!~) *([0-9a-zA-Z_\*]+)}
|
|
||||||
# Regexp for bool attr (e.g., is_hierarchical) - anchored for standalone use
|
|
||||||
set filter_regexp_bool {^@?([a-zA-Z_]+)$}
|
|
||||||
# Regexp for wildcard attr (e.g., full_name <?> *blk*)
|
|
||||||
set filter_regexp_wild_op {@?([a-zA-Z_]+) *(.+) *([0-9a-zA-Z_\*]+)}
|
|
||||||
# Regexp for term in compound expression (no anchors)
|
|
||||||
set filter_regexp_term {@?([a-zA-Z_]+)( *(==|!=|=~|!~) *([0-9a-zA-Z_\*]+))?}
|
|
||||||
set filter_or_regexp "($filter_regexp_term) *\\|\\| *($filter_regexp_term)"
|
|
||||||
set filter_and_regexp "($filter_regexp_term) *&& *($filter_regexp_term)"
|
|
||||||
set filtered_objects {}
|
|
||||||
# Ignore sub-exprs in filter_regexp for expr2 match var.
|
|
||||||
if { [regexp $filter_or_regexp $filter ignore expr1 ignore ignore ignore ignore expr2] } {
|
|
||||||
set filtered_objects1 [filter_objs $expr1 $objects $filter_function $object_type]
|
|
||||||
set filtered_objects2 [filter_objs $expr2 $objects $filter_function $object_type]
|
|
||||||
set filtered_objects [concat $filtered_objects1 $filtered_objects2]
|
|
||||||
} elseif { [regexp $filter_and_regexp $filter ignore expr1 ignore ignore ignore ignore expr2] } {
|
|
||||||
set filtered_objects [filter_objs $expr1 $objects $filter_function $object_type]
|
|
||||||
set filtered_objects [filter_objs $expr2 $filtered_objects $filter_function $object_type]
|
|
||||||
} elseif { [regexp $filter_regexp_op $filter ignore attr_name op arg] } {
|
|
||||||
set filtered_objects [$filter_function $attr_name $op $arg $objects]
|
|
||||||
} elseif { [regexp $filter_regexp_bool $filter ignore attr_name] } {
|
|
||||||
# Bool property: use <attr_name>==1 by default.
|
|
||||||
set filtered_objects [$filter_function $attr_name "==" "1" $objects]
|
|
||||||
} elseif { [regexp $filter_regexp_wild_op $filter ignore attr_name op arg] } {
|
|
||||||
sta_error 336 "unknown filter operand."
|
|
||||||
} else {
|
|
||||||
sta_error 350 "unsupported $object_type -filter expression."
|
|
||||||
}
|
|
||||||
return $filtered_objects
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################
|
|
||||||
|
|
||||||
define_cmd_args "get_cells" \
|
define_cmd_args "get_cells" \
|
||||||
{[-hierarchical] [-hsc separator] [-filter expr]\
|
{[-hierarchical] [-hsc separator] [-filter expr]\
|
||||||
[-regexp] [-nocase] [-quiet] [-of_objects objects] [patterns]}
|
[-regexp] [-nocase] [-quiet] [-of_objects objects] [patterns]}
|
||||||
|
|
@ -429,7 +393,7 @@ proc get_cells { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set insts [filter_objs $keys(-filter) $insts filter_insts "instance"]
|
set insts [filter_insts $keys(-filter) $insts 1]
|
||||||
}
|
}
|
||||||
return $insts
|
return $insts
|
||||||
}
|
}
|
||||||
|
|
@ -472,7 +436,7 @@ proc get_clocks { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set clocks [filter_objs $keys(-filter) $clocks filter_clocks "clock"]
|
set clocks [filter_clocks $keys(-filter) $clocks 1]
|
||||||
}
|
}
|
||||||
return $clocks
|
return $clocks
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +517,7 @@ proc get_lib_cells { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set cells [filter_objs $keys(-filter) $cells filter_lib_cells "liberty cell"]
|
set cells [filter_lib_cells $keys(-filter) $cells 1]
|
||||||
}
|
}
|
||||||
return $cells
|
return $cells
|
||||||
}
|
}
|
||||||
|
|
@ -657,7 +621,7 @@ proc get_lib_pins { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set ports [filter_objs $keys(-filter) $ports filter_lib_pins "liberty port"]
|
set ports [filter_lib_pins $keys(-filter) $ports 1]
|
||||||
}
|
}
|
||||||
return $ports
|
return $ports
|
||||||
}
|
}
|
||||||
|
|
@ -707,7 +671,7 @@ proc get_libs { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set libs [filter_objs $keys(-filter) $libs filter_liberty_libraries "liberty library"]
|
set libs [filter_liberty_libraries $keys(-filter) $libs 1]
|
||||||
}
|
}
|
||||||
return $libs
|
return $libs
|
||||||
}
|
}
|
||||||
|
|
@ -808,7 +772,7 @@ proc get_nets { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set nets [filter_objs $keys(-filter) $nets filter_nets "net"]
|
set nets [filter_nets $keys(-filter) $nets 1]
|
||||||
}
|
}
|
||||||
return $nets
|
return $nets
|
||||||
}
|
}
|
||||||
|
|
@ -899,7 +863,7 @@ proc get_pins { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set pins [filter_objs $keys(-filter) $pins filter_pins "pin"]
|
set pins [filter_pins $keys(-filter) $pins 1]
|
||||||
}
|
}
|
||||||
return $pins
|
return $pins
|
||||||
}
|
}
|
||||||
|
|
@ -955,7 +919,7 @@ proc get_ports { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set ports [filter_objs $keys(-filter) $ports filter_ports "port"]
|
set ports [filter_ports $keys(-filter) $ports 1]
|
||||||
}
|
}
|
||||||
return $ports
|
return $ports
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ BfsIterator::visitParallel(Level to_level,
|
||||||
for (size_t k = 0; k < thread_count; k++) {
|
for (size_t k = 0; k < thread_count; k++) {
|
||||||
// Last thread gets the left overs.
|
// Last thread gets the left overs.
|
||||||
size_t to = (k == thread_count - 1) ? vertex_count : from + chunk_size;
|
size_t to = (k == thread_count - 1) ? vertex_count : from + chunk_size;
|
||||||
dispatch_queue_->dispatch([=, this](int) {
|
dispatch_queue_->dispatch([=, this](size_t) {
|
||||||
for (size_t i = from; i < to; i++) {
|
for (size_t i = from; i < to; i++) {
|
||||||
Vertex *vertex = level_vertices[i];
|
Vertex *vertex = level_vertices[i];
|
||||||
if (vertex) {
|
if (vertex) {
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
|
||||||
std::vector<ClkSkewMap> partial_skews(thread_count_);
|
std::vector<ClkSkewMap> partial_skews(thread_count_);
|
||||||
for (Vertex *src_vertex : graph_->regClkVertices()) {
|
for (Vertex *src_vertex : graph_->regClkVertices()) {
|
||||||
if (hasClkPaths(src_vertex)) {
|
if (hasClkPaths(src_vertex)) {
|
||||||
dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) {
|
dispatch_queue_->dispatch([this, src_vertex, &partial_skews](size_t i) {
|
||||||
findClkSkewFrom(src_vertex, partial_skews[i]);
|
findClkSkewFrom(src_vertex, partial_skews[i]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1025,8 +1025,8 @@ PathGroups::makeGroupPathEnds(VertexSet &endpoints,
|
||||||
MakeEndpointPathEnds(visitor, Scene::sceneSet(scenes),
|
MakeEndpointPathEnds(visitor, Scene::sceneSet(scenes),
|
||||||
min_max, this));
|
min_max, this));
|
||||||
for (const auto endpoint : endpoints) {
|
for (const auto endpoint : endpoints) {
|
||||||
dispatch_queue_->dispatch( [endpoint, &visitors](int i)
|
dispatch_queue_->dispatch(
|
||||||
{ visitors[i].visit(endpoint); } );
|
[endpoint, &visitors](size_t i) { visitors[i].visit(endpoint); });
|
||||||
}
|
}
|
||||||
dispatch_queue_->finishTasks();
|
dispatch_queue_->finishTasks();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1102,9 +1102,7 @@ Search::findArrivalsSeed()
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
|
ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
|
||||||
PathVisitor(nullptr,
|
PathVisitor(nullptr, false, sta)
|
||||||
false,
|
|
||||||
sta)
|
|
||||||
{
|
{
|
||||||
init0();
|
init0();
|
||||||
init(true, false, nullptr);
|
init(true, false, nullptr);
|
||||||
|
|
@ -1114,9 +1112,7 @@ ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
|
||||||
ArrivalVisitor::ArrivalVisitor(bool always_to_endpoints,
|
ArrivalVisitor::ArrivalVisitor(bool always_to_endpoints,
|
||||||
SearchPred *pred,
|
SearchPred *pred,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
PathVisitor(pred,
|
PathVisitor(pred, true, sta)
|
||||||
true,
|
|
||||||
sta)
|
|
||||||
{
|
{
|
||||||
init0();
|
init0();
|
||||||
init(always_to_endpoints, false, pred);
|
init(always_to_endpoints, false, pred);
|
||||||
|
|
@ -1997,11 +1993,13 @@ PathVisitor::visitFaninPaths(Vertex *to_vertex)
|
||||||
VertexInEdgeIterator edge_iter(to_vertex, graph_);
|
VertexInEdgeIterator edge_iter(to_vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *from_vertex = edge->from(graph_);
|
if (!edge->role()->isTimingCheck()) {
|
||||||
const Pin *from_pin = from_vertex->pin();
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
const Pin *to_pin = to_vertex->pin();
|
const Pin *from_pin = from_vertex->pin();
|
||||||
if (!visitEdge(from_pin, from_vertex, edge, to_pin, to_vertex))
|
const Pin *to_pin = to_vertex->pin();
|
||||||
break;
|
if (!visitEdge(from_pin, from_vertex, edge, to_pin, to_vertex))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@ proc get_timing_edges_cmd { cmd cmd_args } {
|
||||||
cmd_usage_error $cmd
|
cmd_usage_error $cmd
|
||||||
}
|
}
|
||||||
if [info exists keys(-filter)] {
|
if [info exists keys(-filter)] {
|
||||||
set arcs [filter_objs $keys(-filter) $arcs filter_timing_arcs "timing arc"]
|
set arcs [filter_timing_arcs $keys(-filter) $arcs 1]
|
||||||
}
|
}
|
||||||
return $arcs
|
return $arcs
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,10 @@ in2
|
||||||
[get_ports -filter direction==output *]
|
[get_ports -filter direction==output *]
|
||||||
out
|
out
|
||||||
[get_cells -filter {name ~= *r1*} *]
|
[get_cells -filter {name ~= *r1*} *]
|
||||||
Error 336: get_filter.tcl line 48, unknown filter operand.
|
Error: 2600 -filter parsing failed at '~= *r1*'.
|
||||||
|
clk1
|
||||||
|
clk2
|
||||||
|
clk3
|
||||||
|
clk1
|
||||||
|
clk2
|
||||||
|
clk3
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@ link_design top
|
||||||
create_clock -name clk -period 500 {clk1 clk2 clk3}
|
create_clock -name clk -period 500 {clk1 clk2 clk3}
|
||||||
create_clock -name vclk -period 1000
|
create_clock -name vclk -period 1000
|
||||||
|
|
||||||
# Test filters for each SDC command
|
# Test filters for each SDC get_* command.
|
||||||
puts {[get_cells -filter liberty_cell==BUFx2_ASAP7_75t_R *]}
|
puts {[get_cells -filter liberty_cell==BUFx2_ASAP7_75t_R *]}
|
||||||
report_object_full_names [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 *]}
|
puts {[get_clocks -filter is_virtual==0 *]}
|
||||||
report_object_full_names [get_clocks -filter is_virtual==0 *]
|
report_object_full_names [get_clocks -filter is_virtual==0 *]
|
||||||
puts {[get_clocks -filter is_virtual==1 *]}
|
puts {[get_clocks -filter is_virtual==1 *]}
|
||||||
|
|
@ -22,22 +23,28 @@ puts {[get_clocks -filter is_virtual||is_generated *]}
|
||||||
report_object_full_names [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 *]}
|
puts {[get_clocks -filter is_virtual==0||is_generated *]}
|
||||||
report_object_full_names [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 *]}
|
puts {[get_lib_cells -filter is_buffer==1 *]}
|
||||||
report_object_full_names [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 *]}
|
puts {[get_lib_cells -filter is_inverter==0 *]}
|
||||||
report_object_full_names [get_lib_cells -filter is_inverter==0 *]
|
report_object_full_names [get_lib_cells -filter is_inverter==0 *]
|
||||||
|
|
||||||
puts {[get_lib_pins -filter direction==input BUFx2_ASAP7_75t_R/*]}
|
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/*]
|
report_object_full_names [get_lib_pins -filter direction==input BUFx2_ASAP7_75t_R/*]
|
||||||
puts {[get_lib_pins -filter direction==output BUFx2_ASAP7_75t_R/*]}
|
puts {[get_lib_pins -filter direction==output BUFx2_ASAP7_75t_R/*]}
|
||||||
report_object_full_names [get_lib_pins -filter direction==output BUFx2_ASAP7_75t_R/*]
|
report_object_full_names [get_lib_pins -filter direction==output BUFx2_ASAP7_75t_R/*]
|
||||||
|
|
||||||
puts {[get_libs -filter name==asap7_small *]}
|
puts {[get_libs -filter name==asap7_small *]}
|
||||||
report_object_full_names [get_libs -filter name==asap7_small *]
|
report_object_full_names [get_libs -filter name==asap7_small *]
|
||||||
|
|
||||||
puts {[get_nets -filter name=~*q *]}
|
puts {[get_nets -filter name=~*q *]}
|
||||||
report_object_full_names [get_nets -filter name=~*q *]
|
report_object_full_names [get_nets -filter name=~*q *]
|
||||||
|
|
||||||
puts {[get_pins -filter direction==input *]}
|
puts {[get_pins -filter direction==input *]}
|
||||||
report_object_full_names [get_pins -filter direction==input *]
|
report_object_full_names [get_pins -filter direction==input *]
|
||||||
puts {[get_pins -filter direction==output *]}
|
puts {[get_pins -filter direction==output *]}
|
||||||
report_object_full_names [get_pins -filter direction==output *]
|
report_object_full_names [get_pins -filter direction==output *]
|
||||||
|
|
||||||
puts {[get_ports -filter direction==input *]}
|
puts {[get_ports -filter direction==input *]}
|
||||||
report_object_full_names [get_ports -filter direction==input *]
|
report_object_full_names [get_ports -filter direction==input *]
|
||||||
puts {[get_ports -filter direction==output *]}
|
puts {[get_ports -filter direction==output *]}
|
||||||
|
|
@ -47,3 +54,10 @@ report_object_full_names [get_ports -filter direction==output *]
|
||||||
puts {[get_cells -filter {name ~= *r1*} *]}
|
puts {[get_cells -filter {name ~= *r1*} *]}
|
||||||
catch {get_cells -filter {name ~= *r1*} *} result
|
catch {get_cells -filter {name ~= *r1*} *} result
|
||||||
puts $result
|
puts $result
|
||||||
|
|
||||||
|
# AND pattern match expr
|
||||||
|
report_object_names [get_ports -filter "direction == input && name =~ clk*" *]
|
||||||
|
# parens around sub-exprs
|
||||||
|
report_object_names [get_ports -filter "(direction == input) && (name =~ clk*)" *]
|
||||||
|
|
||||||
|
sta::filter_expr_to_postfix "direction == input && name =~ clk* && is_clock" 1
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,6 @@ proc run_tests {} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_failure_file
|
write_failure_file
|
||||||
write_diff_file
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proc run_test { test } {
|
proc run_test { test } {
|
||||||
|
|
@ -268,6 +267,8 @@ proc run_tests_parallel {} {
|
||||||
vwait reg_parallel_job_done
|
vwait reg_parallel_job_done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# update results/failures and results/diffs
|
||||||
|
write_failure_file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,23 +435,23 @@ proc test_failed { test reason } {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc write_failure_file {} {
|
proc write_failure_file {} {
|
||||||
global failure_file failed_tests
|
global failure_file failed_tests failed_tests_summery
|
||||||
|
global diff_file diff_options
|
||||||
|
|
||||||
set ch [open $failure_file "w"]
|
set fail_ch [open $failure_file "a"]
|
||||||
foreach test $failed_tests {
|
foreach test $failed_tests {
|
||||||
puts $ch $test
|
if { ![info exists failed_tests_summery($test)] } {
|
||||||
}
|
puts $fail_ch $test
|
||||||
close $ch
|
|
||||||
}
|
|
||||||
|
|
||||||
proc write_diff_file {} {
|
# Append diff to results/diffs
|
||||||
global diff_file diff_options failed_tests
|
set log_file [test_log_file $test]
|
||||||
|
set ok_file [test_ok_file $test]
|
||||||
|
catch [concat exec diff $diff_options $ok_file $log_file >> $diff_file]
|
||||||
|
|
||||||
foreach test $failed_tests {
|
set failed_tests_summery($test) 1
|
||||||
set log_file [test_log_file $test]
|
}
|
||||||
set ok_file [test_ok_file $test]
|
|
||||||
catch [concat exec diff $diff_options $ok_file $log_file >> $diff_file]
|
|
||||||
}
|
}
|
||||||
|
close $fail_ch
|
||||||
}
|
}
|
||||||
|
|
||||||
# Error messages can be found in "valgrind/memcheck/mc_errcontext.c".
|
# Error messages can be found in "valgrind/memcheck/mc_errcontext.c".
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue