Merge pull request #158 from openroadie/master
Latest STA code (performance fix)
This commit is contained in:
commit
8de844d9d8
|
|
@ -301,7 +301,8 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
|
|||
Net *net = network_->net(drvr_pin);
|
||||
parasitics_->deleteParasiticNetwork(net, parasitic_ap);
|
||||
}
|
||||
reduced_parasitic_drvrs_.push_back(drvr_pin);
|
||||
// Arnoldi parasitics their own class that are not saved in the parasitic db.
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
return parasitic;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1550,7 +1550,6 @@ DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
|
|||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
dmp_alg_ = nullptr;
|
||||
input_port_ = true;
|
||||
RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ protected:
|
|||
double rpi,
|
||||
double c1);
|
||||
|
||||
bool input_port_;
|
||||
static bool unsuppored_model_warned_;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ RCDelayCalc::inputPortDelay(const Pin *,
|
|||
drvr_cell_ = nullptr;
|
||||
drvr_library_ = network_->defaultLibertyLibrary();
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
input_port_ = true;
|
||||
}
|
||||
|
||||
// For DSPF on an input port the elmore delay is used as the time
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ protected:
|
|||
|
||||
const LibertyCell *drvr_cell_;
|
||||
const Parasitic *drvr_parasitic_;
|
||||
bool input_port_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ SimpleRCDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew)
|
||||
{
|
||||
input_port_ = false;
|
||||
drvr_parasitic_ = drvr_parasitic;
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
drvr_cell_ = drvr_cell;
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -403,7 +403,7 @@ delayAsString(const Delay &delay,
|
|||
if (sta->pocvEnabled()) {
|
||||
float sigma_early = delay.sigma(EarlyLate::early());
|
||||
float sigma_late = delay.sigma(EarlyLate::late());
|
||||
return stringPrintTmp("%s[%s : %s]",
|
||||
return stringPrintTmp("%s[%s:%s]",
|
||||
unit->asString(delay.mean(), digits),
|
||||
unit->asString(sigma_early, digits),
|
||||
unit->asString(sigma_late, digits));
|
||||
|
|
|
|||
|
|
@ -136,12 +136,6 @@ enum class TableAxisVariable {
|
|||
enum class PathType { clk, data, clk_and_data };
|
||||
const int path_type_count = 2;
|
||||
|
||||
// Rise/fall to rise/fall.
|
||||
const int timing_arc_index_bit_count = 2;
|
||||
const int timing_arc_index_max = (1<<timing_arc_index_bit_count)-1;
|
||||
const int timing_arc_set_index_bit_count = 18;
|
||||
const int timing_arc_set_index_max=(1<<timing_arc_set_index_bit_count)-1;
|
||||
|
||||
class LibertyPortNameLess
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ public:
|
|||
void findAllArrivals();
|
||||
// Find all arrivals (without latch propagation).
|
||||
void findArrivals();
|
||||
virtual void findAllArrivals(VertexVisitor *visitor);
|
||||
// Find arrival times up thru level.
|
||||
void findArrivals(Level level);
|
||||
void findRequireds();
|
||||
|
|
@ -177,9 +176,12 @@ public:
|
|||
bool isClock(const Vertex *vertex) const;
|
||||
// Vertices on propagated generated clock source paths.
|
||||
bool isGenClkSrc(const Vertex *vertex) const;
|
||||
// The set of clocks that arrive at vertex.
|
||||
// The set of clocks that arrive at vertex in the clock network.
|
||||
ClockSet clocks(const Vertex *vertex) const;
|
||||
ClockSet clocks(const Pin *pin) const;
|
||||
// Clock domains for a vertex.
|
||||
ClockSet clockDomains(const Vertex *vertex) const;
|
||||
ClockSet clockDomains(const Pin *pin) const;
|
||||
void visitStartpoints(VertexVisitor *visitor);
|
||||
void visitEndpoints(VertexVisitor *visitor);
|
||||
bool havePathGroups() const;
|
||||
|
|
@ -346,7 +348,9 @@ public:
|
|||
void findFilteredArrivals(ExceptionFrom *from,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
bool unconstrained);
|
||||
bool unconstrained,
|
||||
bool thru_latches);
|
||||
VertexSeq filteredEndpoints();
|
||||
|
||||
protected:
|
||||
void init(StaState *sta);
|
||||
|
|
@ -445,8 +449,8 @@ protected:
|
|||
Vertex *vertex);
|
||||
void findClkArrivals1();
|
||||
|
||||
virtual void findArrivals(Level level,
|
||||
VertexVisitor *arrival_visitor);
|
||||
void findAllArrivals(bool thru_latches);
|
||||
void findArrivals1(Level level);
|
||||
Tag *mutateTag(Tag *from_tag,
|
||||
const Pin *from_pin,
|
||||
const RiseFall *from_rf,
|
||||
|
|
@ -471,8 +475,8 @@ protected:
|
|||
bool havePendingLatchOutputs();
|
||||
void clearPendingLatchOutputs();
|
||||
void enqueuePendingLatchOutputs();
|
||||
void findFilteredArrivals();
|
||||
void findArrivals1();
|
||||
void findFilteredArrivals(bool thru_latches);
|
||||
void findArrivalsSeed();
|
||||
void seedFilterStarts();
|
||||
bool hasEnabledChecks(Vertex *vertex) const;
|
||||
virtual float timingDerate(Vertex *from_vertex,
|
||||
|
|
@ -525,6 +529,9 @@ protected:
|
|||
void clocks(const Vertex *vertex,
|
||||
// Return value.
|
||||
ClockSet &clks) const;
|
||||
void clockDomains(const Vertex *vertex,
|
||||
// Return value.
|
||||
ClockSet &clks) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -598,6 +605,7 @@ protected:
|
|||
// filter_from_ is owned by filter_ if it exists.
|
||||
ExceptionFrom *filter_from_;
|
||||
ExceptionTo *filter_to_;
|
||||
VertexSet *filtered_arrivals_;
|
||||
bool found_downstream_clk_pins_;
|
||||
PathGroups *path_groups_;
|
||||
VisitPathEnds *visit_path_ends_;
|
||||
|
|
|
|||
|
|
@ -458,36 +458,36 @@ public:
|
|||
void setCaseAnalysis(Pin *pin,
|
||||
LogicValue value);
|
||||
void removeCaseAnalysis(Pin *pin);
|
||||
void setInputDelay(Pin *pin,
|
||||
void setInputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
Pin *ref_pin,
|
||||
const Pin *ref_pin,
|
||||
bool source_latency_included,
|
||||
bool network_latency_included,
|
||||
const MinMaxAll *min_max,
|
||||
bool add,
|
||||
float delay);
|
||||
void removeInputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max);
|
||||
void setOutputDelay(Pin *pin,
|
||||
void removeInputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
const MinMaxAll *min_max);
|
||||
void setOutputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
Pin *ref_pin,
|
||||
const Pin *ref_pin,
|
||||
bool source_latency_included,
|
||||
bool network_latency_included,
|
||||
const MinMaxAll *min_max,
|
||||
bool add,
|
||||
float delay);
|
||||
void removeOutputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max);
|
||||
void removeOutputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
const MinMaxAll *min_max);
|
||||
void makeFalsePath(ExceptionFrom *from,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
|
|
@ -595,8 +595,10 @@ public:
|
|||
bool thru_disabled,
|
||||
bool thru_constants);
|
||||
|
||||
// The set of clocks that reach pin.
|
||||
// The set of clocks that arrive at vertex in the clock network.
|
||||
ClockSet clocks(const Pin *pin);
|
||||
// Clock domains for a pin.
|
||||
ClockSet clockDomains(const Pin *pin);
|
||||
|
||||
void checkSlewLimitPreamble();
|
||||
// Return pins with the min/max slew limit slack.
|
||||
|
|
|
|||
|
|
@ -361,8 +361,7 @@ public:
|
|||
float &value,
|
||||
bool &extrapolated) const;
|
||||
float findValue(float axis_value1) const;
|
||||
float findValueClip(float axis_value1,
|
||||
float clip_value) const;
|
||||
float findValueClip(float axis_value1) const;
|
||||
FloatSeq *values() const { return values_; }
|
||||
using Table::findValue;
|
||||
|
||||
|
|
@ -501,9 +500,11 @@ class OutputWaveforms
|
|||
public:
|
||||
OutputWaveforms(TableAxisPtr slew_axis,
|
||||
TableAxisPtr cap_axis,
|
||||
const RiseFall *rf,
|
||||
Table1Seq ¤t_waveforms,
|
||||
Table1 *ref_times);
|
||||
~OutputWaveforms();
|
||||
const RiseFall *rf() const { return rf_; }
|
||||
Table1 voltageWaveform(float in_slew,
|
||||
float load_cap);
|
||||
Table1 currentWaveform(float slew,
|
||||
|
|
@ -519,6 +520,7 @@ private:
|
|||
TableAxisPtr slew_axis_;
|
||||
// Column.
|
||||
TableAxisPtr cap_axis_;
|
||||
const RiseFall *rf_;
|
||||
Table1Seq current_waveforms_;
|
||||
Table1Seq voltage_waveforms_;
|
||||
Table1 *ref_times_;
|
||||
|
|
|
|||
|
|
@ -1211,8 +1211,6 @@ unsigned
|
|||
LibertyCell::addTimingArcSet(TimingArcSet *arc_set)
|
||||
{
|
||||
int set_index = timing_arc_sets_.size();
|
||||
if (set_index > timing_arc_set_index_max)
|
||||
criticalError(235, "timing arc set max index exceeded");
|
||||
timing_arc_sets_.push_back(arc_set);
|
||||
|
||||
LibertyPort *from = arc_set->from();
|
||||
|
|
|
|||
|
|
@ -2532,7 +2532,7 @@ LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
|
|||
waveform->cap());
|
||||
}
|
||||
Table1 *ref_time_tbl = new Table1(ref_times, slew_axis);
|
||||
OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis,
|
||||
OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, rf_,
|
||||
current_waveforms,
|
||||
ref_time_tbl);
|
||||
timing_->setOutputWaveforms(rf_, output_current);
|
||||
|
|
|
|||
|
|
@ -871,35 +871,8 @@ Table1::findValue(float axis_value1,
|
|||
float
|
||||
Table1::findValue(float axis_value1) const
|
||||
{
|
||||
float value;
|
||||
bool extrapolated;
|
||||
findValue(axis_value1, value, extrapolated);
|
||||
return value;
|
||||
}
|
||||
|
||||
float
|
||||
Table1::findValueClip(float axis_value1,
|
||||
float clip_value) const
|
||||
{
|
||||
float value;
|
||||
bool extrapolated;
|
||||
findValue(axis_value1, value, extrapolated);
|
||||
if (extrapolated)
|
||||
return clip_value;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
Table1::findValue(float axis_value1,
|
||||
// Return values.
|
||||
float &value,
|
||||
bool &extrapolated) const
|
||||
{
|
||||
if (axis1_->size() == 1) {
|
||||
value = this->value(axis_value1);
|
||||
extrapolated = false;
|
||||
}
|
||||
if (axis1_->size() == 1)
|
||||
return this->value(axis_value1);
|
||||
else {
|
||||
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
|
||||
float x1 = axis_value1;
|
||||
|
|
@ -908,8 +881,30 @@ Table1::findValue(float axis_value1,
|
|||
float y1 = this->value(axis_index1);
|
||||
float y2 = this->value(axis_index1 + 1);
|
||||
float dx1 = (x1 - x1l) / (x1u - x1l);
|
||||
value = (1 - dx1) * y1 + dx1 * y2;
|
||||
extrapolated = (x1 < x1l || x1 >= x1u);
|
||||
return (1 - dx1) * y1 + dx1 * y2;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
Table1::findValueClip(float axis_value1) const
|
||||
{
|
||||
if (axis1_->size() == 1)
|
||||
return this->value(axis_value1);
|
||||
else {
|
||||
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
|
||||
float x1 = axis_value1;
|
||||
float x1l = axis1_->axisValue(axis_index1);
|
||||
float x1u = axis1_->axisValue(axis_index1 + 1);
|
||||
if (x1 < x1l)
|
||||
return this->value(0);
|
||||
else if (x1 > x1u)
|
||||
return this->value(axis1_->size() - 1);
|
||||
else {
|
||||
float y1 = this->value(axis_index1);
|
||||
float y2 = this->value(axis_index1 + 1);
|
||||
float dx1 = (x1 - x1l) / (x1u - x1l);
|
||||
return (1 - dx1) * y1 + dx1 * y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1584,10 +1579,12 @@ tableVariableUnit(TableAxisVariable variable,
|
|||
|
||||
OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
|
||||
TableAxisPtr cap_axis,
|
||||
const RiseFall *rf,
|
||||
Table1Seq ¤t_waveforms,
|
||||
Table1 *ref_times) :
|
||||
slew_axis_(slew_axis),
|
||||
cap_axis_(cap_axis),
|
||||
rf_(rf),
|
||||
current_waveforms_(current_waveforms),
|
||||
voltage_waveforms_(current_waveforms.size()),
|
||||
ref_times_(ref_times)
|
||||
|
|
@ -1655,7 +1652,6 @@ OutputWaveforms::voltageWaveform(float slew,
|
|||
time_values);
|
||||
|
||||
// Interpolate waveform samples at time steps.
|
||||
float value = values00->value(values00->values()->size() - 1);
|
||||
size_t index1 = slew_index;
|
||||
size_t index2 = cap_index;
|
||||
float x1 = slew;
|
||||
|
|
@ -1667,30 +1663,26 @@ OutputWaveforms::voltageWaveform(float slew,
|
|||
float x2u = cap_axis_->axisValue(index2 + 1);
|
||||
float dx2 = (x2 - x2l) / (x2u - x2l);
|
||||
FloatSeq *values = new FloatSeq;
|
||||
bool waveform_started = false;
|
||||
float prev_value = 0.0;
|
||||
constexpr float value_tol = .01;
|
||||
float value_end = value * (1.0 - value_tol);
|
||||
constexpr float value_tol = .0001;
|
||||
for (size_t i = 0; i <= time_step_count; i++) {
|
||||
float time = time_min + time_step * i;
|
||||
float y00 = values00->findValue(time);
|
||||
float y10 = values10->findValue(time);
|
||||
float y11 = values11->findValue(time);
|
||||
float y01 = values01->findValue(time);
|
||||
float voltage
|
||||
if (time > time_max)
|
||||
break;
|
||||
float y00 = values00->findValueClip(time);
|
||||
float y10 = values10->findValueClip(time);
|
||||
float y11 = values11->findValueClip(time);
|
||||
float y01 = values01->findValueClip(time);
|
||||
float value
|
||||
= (1 - dx1) * (1 - dx2) * y00
|
||||
+ dx1 * (1 - dx2) * y10
|
||||
+ dx1 * dx2 * y11
|
||||
+ (1 - dx1) * dx2 * y01;
|
||||
if (voltage > value_tol)
|
||||
waveform_started = true;
|
||||
if (waveform_started) {
|
||||
if (i == 0 || abs(value - prev_value) > value_tol) {
|
||||
time_values->push_back(time);
|
||||
values->push_back(voltage);
|
||||
values->push_back(value);
|
||||
}
|
||||
if (prev_value > value_end)
|
||||
break;
|
||||
prev_value = voltage;
|
||||
prev_value = value;
|
||||
}
|
||||
return Table1(values, time_axis);
|
||||
}
|
||||
|
|
@ -1713,7 +1705,8 @@ OutputWaveforms::voltageWaveform(size_t wave_index,
|
|||
float prev_current = currents->value(0);
|
||||
float voltage = 0.0;
|
||||
voltages1->push_back(voltage);
|
||||
bool invert = currents->value(time_axis->size() - 1) < 0.0;
|
||||
bool always_rise = true;
|
||||
bool invert = (always_rise && rf_ == RiseFall::fall());
|
||||
for (size_t i = 1; i < time_axis->size(); i++) {
|
||||
float time = time_axis->axisValue(i);
|
||||
float current = currents->value(i);
|
||||
|
|
@ -1723,6 +1716,10 @@ OutputWaveforms::voltageWaveform(size_t wave_index,
|
|||
prev_time = time;
|
||||
prev_current = current;
|
||||
}
|
||||
if (!always_rise && rf_ == RiseFall::fall()) {
|
||||
for (size_t i = 0; i < voltages1->size(); i++)
|
||||
(*voltages1)[i] -= voltage;
|
||||
}
|
||||
}
|
||||
return voltages;
|
||||
}
|
||||
|
|
@ -1773,21 +1770,26 @@ OutputWaveforms::currentWaveform(float slew,
|
|||
float x2u = cap_axis_->axisValue(index2 + 1);
|
||||
float dx2 = (x2 - x2l) / (x2u - x2l);
|
||||
FloatSeq *values = new FloatSeq;
|
||||
float prev_value = 0.0;
|
||||
constexpr float value_tol = 1e-6;
|
||||
for (size_t i = 0; i <= time_step_count; i++) {
|
||||
float time = time_min + time_step * i;
|
||||
float y00 = values00->findValueClip(time, 0.0);
|
||||
float y10 = values10->findValueClip(time, 0.0);
|
||||
float y11 = values11->findValueClip(time, 0.0);
|
||||
float y01 = values01->findValueClip(time, 0.0);
|
||||
if (time > time_max)
|
||||
break;
|
||||
float y00 = values00->findValueClip(time);
|
||||
float y10 = values10->findValueClip(time);
|
||||
float y11 = values11->findValueClip(time);
|
||||
float y01 = values01->findValueClip(time);
|
||||
float value
|
||||
= (1 - dx1) * (1 - dx2) * y00
|
||||
+ dx1 * (1 - dx2) * y10
|
||||
+ dx1 * dx2 * y11
|
||||
+ (1 - dx1) * dx2 * y01;
|
||||
time_values->push_back(time);
|
||||
values->push_back(value);
|
||||
if (time > time_max)
|
||||
break;
|
||||
if (i == 0 || abs(value - prev_value) > value_tol) {
|
||||
time_values->push_back(time);
|
||||
values->push_back(value);
|
||||
}
|
||||
prev_value = value;
|
||||
}
|
||||
return Table1(values, time_axis);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,8 @@ TimingArcIndex
|
|||
TimingArcSet::addTimingArc(TimingArc *arc)
|
||||
{
|
||||
TimingArcIndex arc_index = arcs_.size();
|
||||
if (arc_index > timing_arc_index_max)
|
||||
// Rise/fall to rise/fall.
|
||||
if (arc_index > RiseFall::index_count * RiseFall::index_count)
|
||||
criticalError(243, "timing arc max index exceeded\n");
|
||||
arcs_.push_back(arc);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
using std::to_string;
|
||||
|
||||
static string
|
||||
escapeDividers(const char *token,
|
||||
const Network *network);
|
||||
|
|
@ -670,12 +672,11 @@ SdcNetwork::findPortsMatching(const Cell *cell,
|
|||
matches = network_->findPortsMatching(cell, &escaped_pattern1);
|
||||
if (matches.empty()) {
|
||||
// Try escaping base foo\[0\][1]
|
||||
string escaped2;
|
||||
string escaped_bus_name = escapeBrackets(bus_name.c_str(), this);
|
||||
stringPrint(escaped2, "%s[%d]",
|
||||
escaped_bus_name.c_str(),
|
||||
index);
|
||||
PatternMatch escaped_pattern2(escaped2.c_str(), pattern);
|
||||
string escaped_name = escapeBrackets(bus_name.c_str(), this);
|
||||
escaped_name += '[';
|
||||
escaped_name += to_string(index);
|
||||
escaped_name += ']';
|
||||
PatternMatch escaped_pattern2(escaped_name.c_str(), pattern);
|
||||
matches = network_->findPortsMatching(cell, &escaped_pattern2);
|
||||
}
|
||||
}
|
||||
|
|
@ -929,8 +930,11 @@ SdcNetwork::visitPinTail(const Instance *instance,
|
|||
Port *port = port_iter->next();
|
||||
const char *port_name = network_->name(port);
|
||||
if (network_->hasMembers(port)) {
|
||||
bool bus_matches = tail->match(port_name)
|
||||
|| tail->match(escapeDividers(port_name, network_));
|
||||
bool bus_matches = tail->match(port_name);
|
||||
if (!bus_matches) {
|
||||
string escaped_name = escapeDividers(port_name, network_);
|
||||
bus_matches = tail->match(escaped_name);
|
||||
}
|
||||
PortMemberIterator *member_iter = network_->memberIterator(port);
|
||||
while (member_iter->hasNext()) {
|
||||
Port *member_port = member_iter->next();
|
||||
|
|
@ -942,8 +946,12 @@ SdcNetwork::visitPinTail(const Instance *instance,
|
|||
}
|
||||
else {
|
||||
const char *member_name = network_->name(member_port);
|
||||
if (tail->match(member_name)
|
||||
|| tail->match(escapeDividers(member_name, network_))) {
|
||||
bool member_matches = tail->match(member_name);
|
||||
if (!member_matches) {
|
||||
string escaped_name = escapeDividers(member_name, network_);
|
||||
member_matches = tail->match(escaped_name);
|
||||
}
|
||||
if (member_matches) {
|
||||
matches.push_back(pin);
|
||||
found_match = true;
|
||||
}
|
||||
|
|
@ -952,13 +960,19 @@ SdcNetwork::visitPinTail(const Instance *instance,
|
|||
}
|
||||
delete member_iter;
|
||||
}
|
||||
else if (tail->match(port_name)
|
||||
|| tail->match(escapeDividers(port_name, network_))) {
|
||||
Pin *pin = network_->findPin(instance, port);
|
||||
if (pin) {
|
||||
matches.push_back(pin);
|
||||
found_match = true;
|
||||
}
|
||||
else {
|
||||
bool port_matches = tail->match(port_name);
|
||||
if (!port_matches) {
|
||||
string escaped_name = escapeDividers(port_name, network_);
|
||||
port_matches = tail->match(escaped_name);
|
||||
}
|
||||
if (port_matches) {
|
||||
Pin *pin = network_->findPin(instance, port);
|
||||
if (pin) {
|
||||
matches.push_back(pin);
|
||||
found_match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete port_iter;
|
||||
|
|
@ -1125,9 +1139,9 @@ SdcNetwork::visitMatches(const Instance *parent,
|
|||
network_->findChildrenMatching(parent, &matcher, matches);
|
||||
if (has_brkts && matches.empty()) {
|
||||
// Look for matches after escaping brackets.
|
||||
const PatternMatch escaped_brkts(escapeBrackets(inst_path, this),
|
||||
pattern);
|
||||
network_->findChildrenMatching(parent, &escaped_brkts, matches);
|
||||
string escaped_brkts = escapeBrackets(inst_path, this);
|
||||
const PatternMatch escaped_pattern(escaped_brkts, pattern);
|
||||
network_->findChildrenMatching(parent, &escaped_pattern, matches);
|
||||
}
|
||||
if (!matches.empty()) {
|
||||
// Found instance matches for the sub-path up to this divider.
|
||||
|
|
|
|||
|
|
@ -1805,8 +1805,8 @@ ExceptionThru::matches(const Pin *from_pin,
|
|||
const Network *network)
|
||||
{
|
||||
EdgePins edge_pins(from_pin, to_pin);
|
||||
return ((pins_ && pins_->hasKey(to_pin))
|
||||
|| (edges_ && edges_->hasKey(edge_pins))
|
||||
return ((pins_ && to_pin && pins_->hasKey(to_pin))
|
||||
|| (edges_ && from_pin && to_pin && edges_->hasKey(edge_pins))
|
||||
|| (nets_ && to_pin && nets_->hasKey(network->net(to_pin)))
|
||||
|| (insts_ && to_pin && insts_->hasKey(network->instance(to_pin))))
|
||||
&& rf_->matches(to_rf);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "MakeTimingModel.hh"
|
||||
#include "MakeTimingModelPvt.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
|
@ -45,16 +46,33 @@ namespace sta {
|
|||
using std::max;
|
||||
using std::make_shared;
|
||||
|
||||
MakeTimingModel::MakeTimingModel(const Corner *corner,
|
||||
LibertyLibrary *
|
||||
makeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename,
|
||||
const Corner *corner,
|
||||
Sta *sta)
|
||||
{
|
||||
MakeTimingModel maker(lib_name, cell_name, filename, corner, sta);
|
||||
return maker.makeTimingModel();
|
||||
}
|
||||
|
||||
MakeTimingModel::MakeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename,
|
||||
const Corner *corner,
|
||||
Sta *sta) :
|
||||
StaState(sta),
|
||||
sta_(sta),
|
||||
cell_(nullptr),
|
||||
lib_name_(lib_name),
|
||||
cell_name_(cell_name),
|
||||
filename_(filename),
|
||||
corner_(corner),
|
||||
cell_(nullptr),
|
||||
min_max_(MinMax::max()),
|
||||
lib_builder_(new LibertyBuilder),
|
||||
tbl_template_index_(1),
|
||||
sdc_backup_(nullptr)
|
||||
sdc_backup_(nullptr),
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -64,15 +82,13 @@ MakeTimingModel::~MakeTimingModel()
|
|||
}
|
||||
|
||||
LibertyLibrary *
|
||||
MakeTimingModel::makeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename)
|
||||
MakeTimingModel::makeTimingModel()
|
||||
{
|
||||
saveSdc();
|
||||
|
||||
tbl_template_index_ = 1;
|
||||
makeLibrary(lib_name, filename);
|
||||
makeCell(cell_name, filename);
|
||||
makeLibrary();
|
||||
makeCell();
|
||||
makePorts();
|
||||
|
||||
sta_->searchPreamble();
|
||||
|
|
@ -87,7 +103,7 @@ MakeTimingModel::makeTimingModel(const char *lib_name,
|
|||
return library_;
|
||||
}
|
||||
|
||||
// Move set_input_delay/set_output_delay/set_load's to the side.
|
||||
// Move sdc commands used by makeTimingModel to the side.
|
||||
void
|
||||
MakeTimingModel::saveSdc()
|
||||
{
|
||||
|
|
@ -109,10 +125,9 @@ MakeTimingModel::restoreSdc()
|
|||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::makeLibrary(const char *lib_name,
|
||||
const char *filename)
|
||||
MakeTimingModel::makeLibrary()
|
||||
{
|
||||
library_ = network_->makeLibertyLibrary(lib_name, filename);
|
||||
library_ = network_->makeLibertyLibrary(lib_name_, filename_);
|
||||
LibertyLibrary *default_lib = network_->defaultLibertyLibrary();
|
||||
*library_->units()->timeUnit() = *default_lib->units()->timeUnit();
|
||||
*library_->units()->capacitanceUnit() = *default_lib->units()->capacitanceUnit();
|
||||
|
|
@ -136,10 +151,9 @@ MakeTimingModel::makeLibrary(const char *lib_name,
|
|||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::makeCell(const char *cell_name,
|
||||
const char *filename)
|
||||
MakeTimingModel::makeCell()
|
||||
{
|
||||
cell_ = lib_builder_->makeCell(library_, cell_name, filename);
|
||||
cell_ = lib_builder_->makeCell(library_, cell_name_, filename_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -202,21 +216,18 @@ public:
|
|||
virtual ~MakeEndTimingArcs() {}
|
||||
virtual PathEndVisitor *copy() const;
|
||||
virtual void visit(PathEnd *path_end);
|
||||
void setInputPin(const Pin *input_pin);
|
||||
void setInputRf(const RiseFall *input_rf);
|
||||
const ClockEdgeDelays &margins() const { return margins_; }
|
||||
|
||||
private:
|
||||
Sta *sta_;
|
||||
const Pin *input_pin_;
|
||||
const RiseFall *input_rf_;
|
||||
ClockEdgeDelays margins_;
|
||||
Sta *sta_;
|
||||
};
|
||||
|
||||
MakeEndTimingArcs::MakeEndTimingArcs(Sta *sta) :
|
||||
sta_(sta),
|
||||
input_pin_(nullptr),
|
||||
input_rf_(nullptr)
|
||||
input_rf_(nullptr),
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -226,13 +237,6 @@ MakeEndTimingArcs::copy() const
|
|||
return new MakeEndTimingArcs(*this);
|
||||
}
|
||||
|
||||
void
|
||||
MakeEndTimingArcs::setInputPin(const Pin *input_pin)
|
||||
{
|
||||
input_pin_ = input_pin;
|
||||
margins_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
MakeEndTimingArcs::setInputRf(const RiseFall *input_rf)
|
||||
{
|
||||
|
|
@ -257,8 +261,7 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
|||
? data_delay - clk_latency + check_margin
|
||||
: clk_latency - data_delay + check_margin;
|
||||
float delay1 = delayAsFloat(margin, MinMax::max(), sta_);
|
||||
debugPrint(debug, "make_timing_model", 2, "%s %s -> %s clock %s %s %s %s",
|
||||
network->pathName(input_pin_),
|
||||
debugPrint(debug, "make_timing_model", 2, "%s -> %s clock %s %s %s %s",
|
||||
input_rf_->shortName(),
|
||||
network->pathName(src_path->pin(sta_)),
|
||||
tgt_clk_edge->name(),
|
||||
|
|
@ -285,44 +288,56 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
|||
void
|
||||
MakeTimingModel::findTimingFromInputs()
|
||||
{
|
||||
VisitPathEnds visit_ends(sta_);
|
||||
MakeEndTimingArcs end_visitor(sta_);
|
||||
InstancePinIterator *input_iter = network_->pinIterator(network_->topInstance());
|
||||
while (input_iter->hasNext()) {
|
||||
Pin *input_pin = input_iter->next();
|
||||
if (network_->direction(input_pin)->isInput()
|
||||
&& !sta_->isClockSrc(input_pin)) {
|
||||
end_visitor.setInputPin(input_pin);
|
||||
OutputPinDelays output_delays;
|
||||
for (RiseFall *input_rf : RiseFall::range()) {
|
||||
RiseFallBoth *input_rf1 = input_rf->asRiseFallBoth();
|
||||
sta_->setInputDelay(input_pin, input_rf1,
|
||||
sdc_->defaultArrivalClock(),
|
||||
sdc_->defaultArrivalClockEdge()->transition(),
|
||||
nullptr, false, false, MinMaxAll::all(), true, 0.0);
|
||||
search_->deleteFilteredArrivals();
|
||||
|
||||
PinSet *from_pins = new PinSet(network_);
|
||||
from_pins->insert(input_pin);
|
||||
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
||||
input_rf1);
|
||||
search_->deleteFilteredArrivals();
|
||||
search_->findFilteredArrivals(from, nullptr, nullptr, false);
|
||||
|
||||
end_visitor.setInputRf(input_rf);
|
||||
for (Vertex *end : *search_->endpoints())
|
||||
visit_ends.visitPathEnds(end, corner_, MinMaxAll::all(), true, &end_visitor);
|
||||
findOutputDelays(input_rf, output_delays);
|
||||
|
||||
sta_->removeInputDelay(input_pin, input_rf1,
|
||||
sdc_->defaultArrivalClock(),
|
||||
sdc_->defaultArrivalClockEdge()->transition(),
|
||||
MinMaxAll::all());
|
||||
}
|
||||
makeSetupHoldTimingArcs(input_pin, end_visitor.margins());
|
||||
makeInputOutputTimingArcs(input_pin, output_delays);
|
||||
}
|
||||
Instance *top_inst = network_->topInstance();
|
||||
Cell *top_cell = network_->cell(top_inst);
|
||||
CellPortBitIterator *port_iter = network_->portBitIterator(top_cell);
|
||||
while (port_iter->hasNext()) {
|
||||
Port *input_port = port_iter->next();
|
||||
if (network_->direction(input_port)->isInput())
|
||||
findTimingFromInput(input_port);
|
||||
}
|
||||
delete port_iter;
|
||||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::findTimingFromInput(Port *input_port)
|
||||
{
|
||||
Instance *top_inst = network_->topInstance();
|
||||
Pin *input_pin = network_->findPin(top_inst, input_port);
|
||||
if (!sta_->isClockSrc(input_pin)) {
|
||||
MakeEndTimingArcs end_visitor(sta_);
|
||||
OutputPinDelays output_delays;
|
||||
for (RiseFall *input_rf : RiseFall::range()) {
|
||||
RiseFallBoth *input_rf1 = input_rf->asRiseFallBoth();
|
||||
sta_->setInputDelay(input_pin, input_rf1,
|
||||
sdc_->defaultArrivalClock(),
|
||||
sdc_->defaultArrivalClockEdge()->transition(),
|
||||
nullptr, false, false, MinMaxAll::all(), true, 0.0);
|
||||
|
||||
PinSet *from_pins = new PinSet(network_);
|
||||
from_pins->insert(input_pin);
|
||||
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
||||
input_rf1);
|
||||
search_->findFilteredArrivals(from, nullptr, nullptr, false, false);
|
||||
|
||||
end_visitor.setInputRf(input_rf);
|
||||
VertexSeq endpoints = search_->filteredEndpoints();
|
||||
VisitPathEnds visit_ends(sta_);
|
||||
for (Vertex *end : endpoints)
|
||||
visit_ends.visitPathEnds(end, corner_, MinMaxAll::all(), true, &end_visitor);
|
||||
findOutputDelays(input_rf, output_delays);
|
||||
search_->deleteFilteredArrivals();
|
||||
|
||||
sta_->removeInputDelay(input_pin, input_rf1,
|
||||
sdc_->defaultArrivalClock(),
|
||||
sdc_->defaultArrivalClockEdge()->transition(),
|
||||
MinMaxAll::all());
|
||||
}
|
||||
makeSetupHoldTimingArcs(input_pin, end_visitor.margins());
|
||||
makeInputOutputTimingArcs(input_pin, output_delays);
|
||||
}
|
||||
delete input_iter;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -570,6 +585,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
|||
drvr_self_delay, drvr_self_slew);
|
||||
|
||||
const TableModel *drvr_table = drvr_gate_model->delayModel();
|
||||
const TableTemplate *drvr_template = drvr_table->tblTemplate();
|
||||
const TableAxisPtr drvr_load_axis = loadCapacitanceAxis(drvr_table);
|
||||
if (drvr_load_axis) {
|
||||
const FloatSeq *drvr_axis_values = drvr_load_axis->values();
|
||||
|
|
@ -593,20 +609,15 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
|||
TableAxisPtr load_axis =
|
||||
std::make_shared<TableAxis>(TableAxisVariable::total_output_net_capacitance,
|
||||
axis_values);
|
||||
|
||||
|
||||
TablePtr delay_table = make_shared<Table1>(load_values, load_axis);
|
||||
TablePtr slew_table = make_shared<Table1>(slew_values, load_axis);
|
||||
|
||||
string template_name = "template_";
|
||||
template_name += std::to_string(tbl_template_index_++);
|
||||
|
||||
TableTemplate *tbl_template = new TableTemplate(template_name.c_str());
|
||||
tbl_template->setAxis1(load_axis);
|
||||
library_->addTableTemplate(tbl_template, TableTemplateType::delay);
|
||||
|
||||
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
||||
TableTemplate *model_template = ensureTableTemplate(drvr_template,
|
||||
load_axis);
|
||||
TableModel *delay_model = new TableModel(delay_table, model_template,
|
||||
ScaleFactorType::cell, rf);
|
||||
TableModel *slew_model = new TableModel(slew_table, tbl_template,
|
||||
TableModel *slew_model = new TableModel(slew_table, model_template,
|
||||
ScaleFactorType::cell, rf);
|
||||
GateTableModel *gate_model = new GateTableModel(delay_model, nullptr,
|
||||
slew_model, nullptr,
|
||||
|
|
@ -624,6 +635,23 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
|||
return makeGateModelScalar(delay, slew, rf);
|
||||
}
|
||||
|
||||
TableTemplate *
|
||||
MakeTimingModel::ensureTableTemplate(const TableTemplate *drvr_template,
|
||||
TableAxisPtr load_axis)
|
||||
{
|
||||
TableTemplate *model_template = template_map_.findKey(drvr_template);
|
||||
if (model_template == nullptr) {
|
||||
string template_name = "template_";
|
||||
template_name += std::to_string(tbl_template_index_++);
|
||||
|
||||
model_template = new TableTemplate(template_name.c_str());
|
||||
model_template->setAxis1(load_axis);
|
||||
library_->addTableTemplate(model_template, TableTemplateType::delay);
|
||||
template_map_[drvr_template] = model_template;
|
||||
}
|
||||
return model_template;
|
||||
}
|
||||
|
||||
TableAxisPtr
|
||||
MakeTimingModel::loadCapacitanceAxis(const TableModel *table)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,81 +16,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "LibertyClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "StaState.hh"
|
||||
#include "RiseFallMinMax.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class LibertyLibrary;
|
||||
class Corner;
|
||||
class Sta;
|
||||
class LibertyBuilder;
|
||||
|
||||
class OutputDelays
|
||||
{
|
||||
public:
|
||||
OutputDelays();
|
||||
TimingSense timingSense() const;
|
||||
|
||||
RiseFallMinMax delays;
|
||||
// input edge -> output edge path exists for unateness
|
||||
bool rf_path_exists[RiseFall::index_count][RiseFall::index_count];
|
||||
};
|
||||
|
||||
typedef std::map<const ClockEdge*, RiseFallMinMax> ClockEdgeDelays;
|
||||
typedef std::map<const Pin *, OutputDelays> OutputPinDelays;
|
||||
|
||||
class MakeTimingModel : public StaState
|
||||
{
|
||||
public:
|
||||
MakeTimingModel(const Corner *corner,
|
||||
Sta *sta);
|
||||
~MakeTimingModel();
|
||||
LibertyLibrary *makeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename);
|
||||
|
||||
private:
|
||||
void makeLibrary(const char *lib_name,
|
||||
const char *filename);
|
||||
void makeCell(const char *cell_name,
|
||||
const char *filename);
|
||||
void makePorts();
|
||||
void checkClock(Clock *clk);
|
||||
void findTimingFromInputs();
|
||||
void findClkedOutputPaths();
|
||||
void findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
const ClockEdgeDelays &clk_margins);
|
||||
void makeInputOutputTimingArcs(const Pin *input_pin,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
TimingModel *makeScalarCheckModel(float value,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf);
|
||||
TimingModel *makeGateModelScalar(Delay delay,
|
||||
Slew slew,
|
||||
RiseFall *rf);
|
||||
TimingModel *makeGateModelTable(const Pin *output_pin,
|
||||
Delay delay,
|
||||
RiseFall *rf);
|
||||
TableAxisPtr loadCapacitanceAxis(const TableModel *table);
|
||||
LibertyPort *modelPort(const Pin *pin);
|
||||
|
||||
void saveSdc();
|
||||
void restoreSdc();
|
||||
|
||||
Sta *sta_;
|
||||
LibertyLibrary *library_;
|
||||
LibertyCell *cell_;
|
||||
const Corner *corner_;
|
||||
MinMax *min_max_;
|
||||
LibertyBuilder *lib_builder_;
|
||||
int tbl_template_index_;
|
||||
Sdc *sdc_backup_;
|
||||
};
|
||||
LibertyLibrary *
|
||||
makeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename,
|
||||
const Corner *corner,
|
||||
Sta *sta);
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "LibertyClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "StaState.hh"
|
||||
#include "RiseFallMinMax.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Sta;
|
||||
class LibertyBuilder;
|
||||
|
||||
class OutputDelays
|
||||
{
|
||||
public:
|
||||
OutputDelays();
|
||||
TimingSense timingSense() const;
|
||||
|
||||
RiseFallMinMax delays;
|
||||
// input edge -> output edge path exists for unateness
|
||||
bool rf_path_exists[RiseFall::index_count][RiseFall::index_count];
|
||||
};
|
||||
|
||||
typedef std::map<const ClockEdge*, RiseFallMinMax> ClockEdgeDelays;
|
||||
typedef std::map<const Pin *, OutputDelays> OutputPinDelays;
|
||||
|
||||
class MakeTimingModel : public StaState
|
||||
{
|
||||
public:
|
||||
MakeTimingModel(const char *lib_name,
|
||||
const char *cell_name,
|
||||
const char *filename,
|
||||
const Corner *corner,
|
||||
Sta *sta);
|
||||
~MakeTimingModel();
|
||||
LibertyLibrary *makeTimingModel();
|
||||
|
||||
private:
|
||||
void makeLibrary();
|
||||
void makeCell();
|
||||
void makePorts();
|
||||
void checkClock(Clock *clk);
|
||||
void findTimingFromInputs();
|
||||
void findTimingFromInput(Port *input_port);
|
||||
void findClkedOutputPaths();
|
||||
void findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
const ClockEdgeDelays &clk_margins);
|
||||
void makeInputOutputTimingArcs(const Pin *input_pin,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
TimingModel *makeScalarCheckModel(float value,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf);
|
||||
TimingModel *makeGateModelScalar(Delay delay,
|
||||
Slew slew,
|
||||
RiseFall *rf);
|
||||
TimingModel *makeGateModelTable(const Pin *output_pin,
|
||||
Delay delay,
|
||||
RiseFall *rf);
|
||||
TableTemplate *ensureTableTemplate(const TableTemplate *drvr_template,
|
||||
TableAxisPtr load_axis);
|
||||
TableAxisPtr loadCapacitanceAxis(const TableModel *table);
|
||||
LibertyPort *modelPort(const Pin *pin);
|
||||
|
||||
void saveSdc();
|
||||
void restoreSdc();
|
||||
|
||||
const char *lib_name_;
|
||||
const char *cell_name_;
|
||||
const char *filename_;
|
||||
const Corner *corner_;
|
||||
LibertyLibrary *library_;
|
||||
LibertyCell *cell_;
|
||||
MinMax *min_max_;
|
||||
LibertyBuilder *lib_builder_;
|
||||
// Output driver table model template to model template.
|
||||
Map<const TableTemplate*, TableTemplate*> template_map_;
|
||||
int tbl_template_index_;
|
||||
Sdc *sdc_backup_;
|
||||
Sta *sta_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -882,6 +882,10 @@ getProperty(const Pin *pin,
|
|||
ClockSet clks = sta->clocks(pin);
|
||||
return PropertyValue(&clks);
|
||||
}
|
||||
else if (stringEqual(property, "clock_domains")) {
|
||||
ClockSet clks = sta->clockDomains(pin);
|
||||
return PropertyValue(&clks);
|
||||
}
|
||||
else if (stringEqual(property, "activity")) {
|
||||
PwrActivity activity = sta->findClkedActivity(pin);
|
||||
return PropertyValue(&activity);
|
||||
|
|
|
|||
129
search/Search.cc
129
search/Search.cc
|
|
@ -250,6 +250,7 @@ Search::init(StaState *sta)
|
|||
filter_ = nullptr;
|
||||
filter_from_ = nullptr;
|
||||
filter_to_ = nullptr;
|
||||
filtered_arrivals_ = new VertexSet(graph_);
|
||||
found_downstream_clk_pins_ = false;
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +288,7 @@ Search::~Search()
|
|||
delete worst_slacks_;
|
||||
delete check_crpr_;
|
||||
delete genclks_;
|
||||
delete filtered_arrivals_;
|
||||
deleteFilter();
|
||||
deletePathGroups();
|
||||
}
|
||||
|
|
@ -403,6 +405,7 @@ Search::deletePaths()
|
|||
Vertex *vertex = vertex_iter.next();
|
||||
vertex->deletePaths();
|
||||
}
|
||||
filtered_arrivals_->clear();
|
||||
graph_->clearArrivals();
|
||||
graph_->clearPrevPaths();
|
||||
arrivals_exist_ = false;
|
||||
|
|
@ -444,7 +447,7 @@ Search::findPathEnds(ExceptionFrom *from,
|
|||
bool clk_gating_setup,
|
||||
bool clk_gating_hold)
|
||||
{
|
||||
findFilteredArrivals(from, thrus, to, unconstrained);
|
||||
findFilteredArrivals(from, thrus, to, unconstrained, true);
|
||||
if (!sdc_->recoveryRemovalChecksEnabled())
|
||||
recovery = removal = false;
|
||||
if (!sdc_->gatedClkChecksEnabled())
|
||||
|
|
@ -466,7 +469,8 @@ void
|
|||
Search::findFilteredArrivals(ExceptionFrom *from,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
bool unconstrained)
|
||||
bool unconstrained,
|
||||
bool thru_latches)
|
||||
{
|
||||
unconstrained_paths_ = unconstrained;
|
||||
// Delete results from last findPathEnds.
|
||||
|
|
@ -480,13 +484,13 @@ Search::findFilteredArrivals(ExceptionFrom *from,
|
|||
|| from->instances()))
|
||||
|| thrus) {
|
||||
filter_ = sdc_->makeFilterPath(from, thrus, nullptr);
|
||||
findFilteredArrivals();
|
||||
findFilteredArrivals(thru_latches);
|
||||
}
|
||||
else
|
||||
// These cases do not require filtered arrivals.
|
||||
// -from clocks
|
||||
// -to
|
||||
findAllArrivals();
|
||||
findAllArrivals(thru_latches);
|
||||
}
|
||||
|
||||
// From/thrus/to are used to make a filter exception. If the last
|
||||
|
|
@ -503,24 +507,34 @@ Search::deleteFilteredArrivals()
|
|||
&& (from->pins()
|
||||
|| from->instances()))
|
||||
|| thrus) {
|
||||
VertexIterator vertex_iter(graph_);
|
||||
while (vertex_iter.hasNext()) {
|
||||
Vertex *vertex = vertex_iter.next();
|
||||
TagGroup *tag_group = tagGroup(vertex);
|
||||
if (tag_group
|
||||
&& tag_group->hasFilterTag()) {
|
||||
// Vertex's tag_group will be deleted.
|
||||
deletePaths(vertex);
|
||||
arrivalInvalid(vertex);
|
||||
requiredInvalid(vertex);
|
||||
}
|
||||
for (Vertex *vertex : *filtered_arrivals_) {
|
||||
deletePaths(vertex);
|
||||
arrivalInvalid(vertex);
|
||||
requiredInvalid(vertex);
|
||||
}
|
||||
bool check_filter_arrivals = false;
|
||||
if (check_filter_arrivals) {
|
||||
VertexIterator vertex_iter(graph_);
|
||||
while (vertex_iter.hasNext()) {
|
||||
Vertex *vertex = vertex_iter.next();
|
||||
TagGroup *tag_group = tagGroup(vertex);
|
||||
if (tag_group
|
||||
&& tag_group->hasFilterTag())
|
||||
filtered_arrivals_->erase(vertex);
|
||||
}
|
||||
if (!filtered_arrivals_->empty()) {
|
||||
report_->reportLine("Filtered verticies mismatch");
|
||||
for (Vertex *vertex : *filtered_arrivals_)
|
||||
report_->reportLine(" %s", vertex->name(network_));
|
||||
}
|
||||
}
|
||||
filtered_arrivals_->clear();
|
||||
deleteFilterTagGroups();
|
||||
deleteFilterClkInfos();
|
||||
deleteFilterTags();
|
||||
}
|
||||
deleteFilter();
|
||||
}
|
||||
deleteFilter();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -567,17 +581,19 @@ Search::deleteFilterClkInfos()
|
|||
}
|
||||
|
||||
void
|
||||
Search::findFilteredArrivals()
|
||||
Search::findFilteredArrivals(bool thru_latches)
|
||||
{
|
||||
findArrivals1();
|
||||
filtered_arrivals_->clear();
|
||||
findArrivalsSeed();
|
||||
seedFilterStarts();
|
||||
Level max_level = levelize_->maxLevel();
|
||||
// Search always_to_endpoint to search from exisiting arrivals at
|
||||
// fanin startpoints to reach -thru/-to endpoints.
|
||||
arrival_visitor_->init(true);
|
||||
// Iterate until data arrivals at all latches stop changing.
|
||||
for (int pass = 1; pass <= 2 || havePendingLatchOutputs() ; pass++) {
|
||||
enqueuePendingLatchOutputs();
|
||||
for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()) ; pass++) {
|
||||
if (thru_latches)
|
||||
enqueuePendingLatchOutputs();
|
||||
debugPrint(debug_, "search", 1, "find arrivals pass %d", pass);
|
||||
int arrival_count = arrival_iter_->visitParallel(max_level,
|
||||
arrival_visitor_);
|
||||
|
|
@ -586,6 +602,17 @@ Search::findFilteredArrivals()
|
|||
arrivals_exist_ = true;
|
||||
}
|
||||
|
||||
VertexSeq
|
||||
Search::filteredEndpoints()
|
||||
{
|
||||
VertexSeq ends;
|
||||
for (Vertex *vertex : *filtered_arrivals_) {
|
||||
if (isEndpoint(vertex))
|
||||
ends.push_back(vertex);
|
||||
}
|
||||
return ends;
|
||||
}
|
||||
|
||||
class SeedFaninsThruHierPin : public HierPinThruVisitor
|
||||
{
|
||||
public:
|
||||
|
|
@ -652,6 +679,7 @@ Search::deleteVertexBefore(Vertex *vertex)
|
|||
deletePaths(vertex);
|
||||
arrival_iter_->deleteVertexBefore(vertex);
|
||||
invalid_arrivals_->erase(vertex);
|
||||
filtered_arrivals_->erase(vertex);
|
||||
}
|
||||
if (requireds_exist_) {
|
||||
required_iter_->deleteVertexBefore(vertex);
|
||||
|
|
@ -926,18 +954,18 @@ Search::visitEndpoints(VertexVisitor *visitor)
|
|||
void
|
||||
Search::findAllArrivals()
|
||||
{
|
||||
arrival_visitor_->init(false);
|
||||
findAllArrivals(arrival_visitor_);
|
||||
findAllArrivals(true);
|
||||
}
|
||||
|
||||
void
|
||||
Search::findAllArrivals(VertexVisitor *arrival_visitor)
|
||||
Search::findAllArrivals(bool thru_latches)
|
||||
{
|
||||
arrival_visitor_->init(false);
|
||||
// Iterate until data arrivals at all latches stop changing.
|
||||
for (int pass = 1; pass == 1 || havePendingLatchOutputs(); pass++) {
|
||||
for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()); pass++) {
|
||||
enqueuePendingLatchOutputs();
|
||||
debugPrint(debug_, "search", 1, "find arrivals pass %d", pass);
|
||||
findArrivals(levelize_->maxLevel(), arrival_visitor);
|
||||
findArrivals1(levelize_->maxLevel());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -971,17 +999,16 @@ void
|
|||
Search::findArrivals(Level level)
|
||||
{
|
||||
arrival_visitor_->init(false);
|
||||
findArrivals(level, arrival_visitor_);
|
||||
findArrivals1(level);
|
||||
}
|
||||
|
||||
void
|
||||
Search::findArrivals(Level level,
|
||||
VertexVisitor *arrival_visitor)
|
||||
Search::findArrivals1(Level level)
|
||||
{
|
||||
debugPrint(debug_, "search", 1, "find arrivals to level %d", level);
|
||||
findArrivals1();
|
||||
findArrivalsSeed();
|
||||
Stats stats(debug_, report_);
|
||||
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor);
|
||||
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
||||
stats.report("Find arrivals");
|
||||
if (arrival_iter_->empty()
|
||||
&& invalid_arrivals_->empty()) {
|
||||
|
|
@ -993,7 +1020,7 @@ Search::findArrivals(Level level,
|
|||
}
|
||||
|
||||
void
|
||||
Search::findArrivals1()
|
||||
Search::findArrivalsSeed()
|
||||
{
|
||||
if (!arrivals_seeded_) {
|
||||
genclks_->ensureInsertionDelays();
|
||||
|
|
@ -2658,6 +2685,8 @@ Search::setVertexArrivals(Vertex *vertex,
|
|||
}
|
||||
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
|
||||
vertex->setTagGroupIndex(tag_group->index());
|
||||
if (tag_group->hasFilterTag())
|
||||
filtered_arrivals_->insert(vertex);
|
||||
|
||||
if (has_requireds) {
|
||||
requiredInvalid(vertex);
|
||||
|
|
@ -2682,6 +2711,8 @@ Search::setVertexArrivals(Vertex *vertex,
|
|||
tag_bldr->copyArrivals(tag_group, arrivals, prev_paths);
|
||||
|
||||
vertex->setTagGroupIndex(tag_group->index());
|
||||
if (tag_group->hasFilterTag())
|
||||
filtered_arrivals_->insert(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2987,6 +3018,42 @@ Search::timingDerate(Vertex *from_vertex,
|
|||
}
|
||||
}
|
||||
|
||||
ClockSet
|
||||
Search::clockDomains(const Vertex *vertex) const
|
||||
{
|
||||
ClockSet clks;
|
||||
clockDomains(vertex, clks);
|
||||
return clks;
|
||||
}
|
||||
|
||||
void
|
||||
Search::clockDomains(const Vertex *vertex,
|
||||
// Return value.
|
||||
ClockSet &clks) const
|
||||
{
|
||||
VertexPathIterator path_iter(const_cast<Vertex*>(vertex), this);
|
||||
while (path_iter.hasNext()) {
|
||||
Path *path = path_iter.next();
|
||||
const Clock *clk = path->clock(this);
|
||||
if (clk)
|
||||
clks.insert(const_cast<Clock *>(clk));
|
||||
}
|
||||
}
|
||||
|
||||
ClockSet
|
||||
Search::clockDomains(const Pin *pin) const
|
||||
{
|
||||
ClockSet clks;
|
||||
Vertex *vertex;
|
||||
Vertex *bidirect_drvr_vertex;
|
||||
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
if (vertex)
|
||||
clockDomains(vertex, clks);
|
||||
if (bidirect_drvr_vertex)
|
||||
clockDomains(bidirect_drvr_vertex, clks);
|
||||
return clks;
|
||||
}
|
||||
|
||||
ClockSet
|
||||
Search::clocks(const Vertex *vertex) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1858,11 +1858,11 @@ Sta::removeCaseAnalysis(Pin *pin)
|
|||
}
|
||||
|
||||
void
|
||||
Sta::setInputDelay(Pin *pin,
|
||||
Sta::setInputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
Pin *ref_pin,
|
||||
const Pin *ref_pin,
|
||||
bool source_latency_included,
|
||||
bool network_latency_included,
|
||||
const MinMaxAll *min_max,
|
||||
|
|
@ -1877,22 +1877,22 @@ Sta::setInputDelay(Pin *pin,
|
|||
}
|
||||
|
||||
void
|
||||
Sta::removeInputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max)
|
||||
Sta::removeInputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
const MinMaxAll *min_max)
|
||||
{
|
||||
sdc_->removeInputDelay(pin, rf, clk, clk_rf, min_max);
|
||||
search_->arrivalInvalid(pin);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::setOutputDelay(Pin *pin,
|
||||
Sta::setOutputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
Pin *ref_pin,
|
||||
const Pin *ref_pin,
|
||||
bool source_latency_included,
|
||||
bool network_latency_included,
|
||||
const MinMaxAll *min_max,
|
||||
|
|
@ -1907,11 +1907,11 @@ Sta::setOutputDelay(Pin *pin,
|
|||
}
|
||||
|
||||
void
|
||||
Sta::removeOutputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max)
|
||||
Sta::removeOutputDelay(const Pin *pin,
|
||||
const RiseFallBoth *rf,
|
||||
const Clock *clk,
|
||||
const RiseFall *clk_rf,
|
||||
const MinMaxAll *min_max)
|
||||
{
|
||||
sdc_->removeOutputDelay(pin, rf, clk, clk_rf, min_max);
|
||||
sdcChangedGraph();
|
||||
|
|
@ -4681,6 +4681,14 @@ Sta::clocks(const Pin *pin)
|
|||
return search_->clocks(pin);
|
||||
}
|
||||
|
||||
ClockSet
|
||||
Sta::clockDomains(const Pin *pin)
|
||||
{
|
||||
searchPreamble();
|
||||
search_->findAllArrivals();
|
||||
return search_->clockDomains(pin);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
InstanceSet
|
||||
|
|
@ -5619,9 +5627,8 @@ Sta::writeTimingModel(const char *lib_name,
|
|||
const char *filename,
|
||||
const Corner *corner)
|
||||
{
|
||||
MakeTimingModel maker(corner, this);
|
||||
LibertyLibrary *library = maker.makeTimingModel(lib_name, cell_name,
|
||||
filename);
|
||||
LibertyLibrary *library = makeTimingModel(lib_name, cell_name, filename,
|
||||
corner, this);
|
||||
writeLiberty(library, filename, this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Tag::asString(bool report_index,
|
|||
string result;
|
||||
|
||||
if (report_index)
|
||||
result += std::to_string(index_);
|
||||
result += std::to_string(index_) + " ";
|
||||
|
||||
if (report_rf_min_max) {
|
||||
const RiseFall *rf = transition();
|
||||
|
|
|
|||
|
|
@ -170,6 +170,8 @@ private:
|
|||
float slewAxisMinValue(TimingArc *arc);
|
||||
float pgPortVoltage(LibertyPgPort *pg_port);
|
||||
void writePrintStmt();
|
||||
float railToRailSlew(float slew,
|
||||
const RiseFall *rf);
|
||||
|
||||
// Stage "accessors".
|
||||
//
|
||||
|
|
@ -408,11 +410,21 @@ WritePathSpice::maxTime()
|
|||
else {
|
||||
float end_slew = findSlew(path_);
|
||||
float arrival = delayAsFloat(path_->arrival(this));
|
||||
float max_time = input_slew / 2.0 + arrival + end_slew;
|
||||
float max_time = railToRailSlew(input_slew, rf) + arrival
|
||||
+ railToRailSlew(end_slew, rf);
|
||||
return max_time;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
WritePathSpice::railToRailSlew(float slew,
|
||||
const RiseFall *rf)
|
||||
{
|
||||
float lower = default_library_->slewLowerThreshold(rf);
|
||||
float upper = default_library_->slewUpperThreshold(rf);
|
||||
return slew / (upper - lower);
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::writeStageInstances()
|
||||
{
|
||||
|
|
@ -492,8 +504,11 @@ WritePathSpice::writeInputWaveform()
|
|||
const RiseFall *rf = input_path->transition(this);
|
||||
TimingArc *next_arc = stageGateArc(input_stage + 1);
|
||||
float slew0 = findSlew(input_path, rf, next_arc);
|
||||
// Arbitrary offset.
|
||||
float time0 = slew0;
|
||||
|
||||
float threshold = default_library_->inputThreshold(rf);
|
||||
float dt = railToRailSlew(slew0, rf);
|
||||
float time0 = dt * threshold;
|
||||
|
||||
int volt_index = 1;
|
||||
const Pin *drvr_pin = stageDrvrPin(input_stage);
|
||||
const Pin *load_pin = stageLoadPin(input_stage);
|
||||
|
|
@ -689,12 +704,11 @@ WritePathSpice::writeWaveformEdge(const RiseFall *rf,
|
|||
volt1 = gnd_voltage_;
|
||||
}
|
||||
float threshold = default_library_->inputThreshold(rf);
|
||||
float lower = default_library_->slewLowerThreshold(rf);
|
||||
float upper = default_library_->slewUpperThreshold(rf);
|
||||
float dt = slew / (upper - lower);
|
||||
float dt = railToRailSlew(slew, rf);
|
||||
float time0 = time - dt * threshold;
|
||||
float time1 = time0 + dt;
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0);
|
||||
if (time0 > 0.0)
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ proc report_delays_wrt_clk { vertex what clk clk_rf } {
|
|||
set rise_fmt [format_delays $rise]
|
||||
set fall_fmt [format_delays $fall]
|
||||
if {$clk != "NULL"} {
|
||||
set clk_str " ([get_name $clk] [rise_fall_short_name $clk_rf])"
|
||||
set clk_str " ([get_name $clk] [rf_short_name $clk_rf])"
|
||||
} else {
|
||||
set clk_str ""
|
||||
}
|
||||
|
|
@ -281,7 +281,7 @@ proc report_wrt_clk { vertex what clk clk_rf } {
|
|||
set rise_fmt [format_times $rise $sta_report_default_digits]
|
||||
set fall_fmt [format_times $fall $sta_report_default_digits]
|
||||
if {$clk != "NULL"} {
|
||||
set clk_str " ([get_name $clk] [rise_fall_short_name $clk_rf])"
|
||||
set clk_str " ([get_name $clk] [rf_short_name $clk_rf])"
|
||||
} else {
|
||||
set clk_str ""
|
||||
}
|
||||
|
|
@ -289,16 +289,6 @@ proc report_wrt_clk { vertex what clk clk_rf } {
|
|||
}
|
||||
}
|
||||
|
||||
proc rise_fall_short_name { rf } {
|
||||
if { $rf == "rise" } {
|
||||
return [rise_short_name]
|
||||
} elseif { $rf == "fall" } {
|
||||
return [fall_short_name]
|
||||
} else {
|
||||
error "unknown transition name $rf"
|
||||
}
|
||||
}
|
||||
|
||||
proc times_are_inf { times } {
|
||||
foreach time $times {
|
||||
if { $time < 1e+10 && $time > -1e+10 } {
|
||||
|
|
@ -1162,5 +1152,43 @@ proc max_fanout_check_slack_limit {} {
|
|||
return [expr [sta::max_fanout_check_slack] / [sta::max_fanout_check_limit]]
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
proc rf_short_name { rf } {
|
||||
if { [rf_is_rise $rf] } {
|
||||
return [rise_short_name]
|
||||
} elseif { [rf_is_fall $rf] } {
|
||||
return [fall_short_name]
|
||||
} else {
|
||||
error "unknown transition name $rf"
|
||||
}
|
||||
}
|
||||
|
||||
proc opposite_rf { rf } {
|
||||
if { [rf_is_rise $rf] } {
|
||||
return "fall"
|
||||
} elseif { [rf_is_fall $rf] } {
|
||||
return "rise"
|
||||
} else {
|
||||
error "opposite_rf unknown transition $rf"
|
||||
}
|
||||
}
|
||||
|
||||
proc rf_is_rise { rf } {
|
||||
if { $rf == "rise" || $rf == "^" || $rf == "r"} {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
proc rf_is_fall { rf } {
|
||||
if { $rf == "fall" || $rf == "v" || $rf == "f"} {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
# sta namespace end.
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue