Merge pull request #158 from openroadie/master

Latest STA code (performance fix)
This commit is contained in:
Harsh Vardhan 2023-04-12 08:49:12 +01:00 committed by GitHub
commit 8de844d9d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 547 additions and 337 deletions

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -88,7 +88,6 @@ protected:
double rpi,
double c1);
bool input_port_;
static bool unsuppored_model_warned_;
private:

View File

@ -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

View File

@ -41,6 +41,7 @@ protected:
const LibertyCell *drvr_cell_;
const Parasitic *drvr_parasitic_;
bool input_port_;
};
} // namespace

View File

@ -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;

Binary file not shown.

Binary file not shown.

View File

@ -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));

View File

@ -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:

View File

@ -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_;

View File

@ -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.

View File

@ -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 &current_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_;

View File

@ -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();

View File

@ -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);

View File

@ -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 &current_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);
}

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
{

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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.
}