write_timing_model min/max_clock_tree_path
commit 327766984f2beedc5c83b0acdab0df48fb61d2ba
Author: James Cherry <cherry@parallaxsw.com>
Date: Wed Oct 4 11:09:38 2023 -0700
write_timing_model min/max_clock_tree_path
Signed-off-by: James Cherry <cherry@parallaxsw.com>
commit 675c1ff6d8cfa90a0d1bd5c8960a8b23e75056a3
Author: James Cherry <cherry@parallaxsw.com>
Date: Wed Oct 4 09:02:39 2023 -0700
min/max_clock_tree_path
Signed-off-by: James Cherry <cherry@parallaxsw.com>
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
dad8c74f75
commit
76d6dd1dae
|
|
@ -191,7 +191,7 @@ Graph::makePortInstanceEdges(const Instance *inst,
|
|||
if ((from_to_port == nullptr
|
||||
|| from_port == from_to_port
|
||||
|| to_port == from_to_port)
|
||||
&& filterEdge(arc_set)) {
|
||||
&& from_port) {
|
||||
Pin *from_pin = network_->findPin(inst, from_port);
|
||||
Pin *to_pin = network_->findPin(inst, to_port);
|
||||
if (from_pin && to_pin) {
|
||||
|
|
|
|||
|
|
@ -232,8 +232,6 @@ protected:
|
|||
Edge *edge);
|
||||
void removeDelays();
|
||||
void removeDelayAnnotated(Edge *edge);
|
||||
// User defined predicate to filter graph edges for liberty timing arcs.
|
||||
virtual bool filterEdge(TimingArcSet *) const { return true; }
|
||||
|
||||
VertexTable *vertices_;
|
||||
EdgeTable *edges_;
|
||||
|
|
|
|||
|
|
@ -110,8 +110,10 @@ public:
|
|||
bool exists = exists_[mm_index];
|
||||
if (exists)
|
||||
return values_[mm_index];
|
||||
else
|
||||
else {
|
||||
criticalError(226, "uninitialized value reference");
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "Map.hh"
|
||||
#include "UnorderedMap.hh"
|
||||
#include "StringSet.hh"
|
||||
#include "MinMaxValues.hh"
|
||||
#include "Delay.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "GraphClass.hh"
|
||||
|
|
@ -113,6 +114,7 @@ typedef Vector<PathVertex> PathVertexSeq;
|
|||
typedef Vector<Slack> SlackSeq;
|
||||
typedef Delay Crpr;
|
||||
typedef Vector<PathRef> PathRefSeq;
|
||||
typedef MinMaxValues<float> ClkDelays[RiseFall::index_count][RiseFall::index_count];
|
||||
|
||||
enum class ReportPathFormat { full,
|
||||
full_clock,
|
||||
|
|
|
|||
|
|
@ -900,12 +900,6 @@ public:
|
|||
void setReportPathDigits(int digits);
|
||||
void setReportPathNoSplit(bool no_split);
|
||||
void setReportPathSigmas(bool report_sigmas);
|
||||
// Report clk skews for clks.
|
||||
void reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
float findWorstClkSkew(const SetupHold *setup_hold);
|
||||
// Header above reportPathEnd results.
|
||||
void reportPathEndHeader();
|
||||
// Footer below reportPathEnd results.
|
||||
|
|
@ -919,6 +913,18 @@ public:
|
|||
void reportPathEnds(PathEndSeq *ends);
|
||||
ReportPath *reportPath() { return report_path_; }
|
||||
void reportPath(Path *path);
|
||||
|
||||
// Report clk skews for clks.
|
||||
void reportClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
float findWorstClkSkew(const SetupHold *setup_hold);
|
||||
// Find min/max/rise/fall delays for clk.
|
||||
void findClkDelays(const Clock *clk,
|
||||
// Return values.
|
||||
ClkDelays &delays);
|
||||
|
||||
// Update arrival times for all pins.
|
||||
// If necessary updateTiming propagates arrivals around latch
|
||||
// loops until the arrivals converge.
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ public:
|
|||
TableModel(TablePtr table,
|
||||
TableTemplate *tbl_template,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf);
|
||||
const RiseFall *rf);
|
||||
void setScaleFactorType(ScaleFactorType type);
|
||||
int order() const;
|
||||
TableTemplate *tblTemplate() const { return tbl_template_; }
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public:
|
|||
void setModeName(const char *name);
|
||||
const char *modeValue() const { return mode_value_; }
|
||||
void setModeValue(const char *value);
|
||||
TimingModel *model(RiseFall *rf) const;
|
||||
void setModel(RiseFall *rf,
|
||||
TimingModel *model(const RiseFall *rf) const;
|
||||
void setModel(const RiseFall *rf,
|
||||
TimingModel *model);
|
||||
float ocvArcDepth() const { return ocv_arc_depth_; }
|
||||
void setOcvArcDepth(float depth);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public:
|
|||
static TimingRole *dataCheckHold() { return data_check_hold_; }
|
||||
static TimingRole *nonSeqSetup() { return non_seq_setup_; }
|
||||
static TimingRole *nonSeqHold() { return non_seq_hold_; }
|
||||
static TimingRole *clockTreePathMin() { return clock_tree_path_min_; }
|
||||
static TimingRole *clockTreePathMax() { return clock_tree_path_max_; }
|
||||
const char *asString() const { return name_; }
|
||||
int index() const { return index_; }
|
||||
bool isWire() const;
|
||||
|
|
@ -125,6 +127,8 @@ private:
|
|||
static TimingRole *data_check_hold_;
|
||||
static TimingRole *non_seq_setup_;
|
||||
static TimingRole *non_seq_hold_;
|
||||
static TimingRole *clock_tree_path_min_;
|
||||
static TimingRole *clock_tree_path_max_;
|
||||
static TimingRoleMap timing_roles_;
|
||||
|
||||
friend class TimingRoleLess;
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ public:
|
|||
RiseFall *opposite() const;
|
||||
|
||||
// for range support.
|
||||
// for (auto tr : RiseFall::range()) {}
|
||||
// for (auto rf : RiseFall::range()) {}
|
||||
static const std::array<RiseFall*, 2> &range() { return range_; }
|
||||
// for (auto tr_index : RiseFall::rangeIndex()) {}
|
||||
// for (auto rf_index : RiseFall::rangeIndex()) {}
|
||||
static const std::array<int, 2> &rangeIndex() { return range_index_; }
|
||||
static const int index_count = 2;
|
||||
static const int index_max = (index_count - 1);
|
||||
|
|
|
|||
|
|
@ -2352,15 +2352,16 @@ bool
|
|||
LibertyPort::less(const LibertyPort *port1,
|
||||
const LibertyPort *port2)
|
||||
{
|
||||
if (port1 == nullptr && port2 != nullptr)
|
||||
return true;
|
||||
if (port1 != nullptr && port2 == nullptr)
|
||||
return false;
|
||||
const char *name1 = port1->name();
|
||||
const char *name2 = port2->name();
|
||||
if (stringEq(name1, name2)) {
|
||||
PortDirection *dir1 = port1->direction();
|
||||
PortDirection *dir2 = port2->direction();
|
||||
if (dir1 == dir2) {
|
||||
}
|
||||
else
|
||||
return dir1->index() < dir2->index();
|
||||
return dir1->index() < dir2->index();
|
||||
}
|
||||
return stringLess(name1, name2);
|
||||
}
|
||||
|
|
@ -2588,8 +2589,8 @@ bool
|
|||
LibertyPortPairLess::operator()(const LibertyPortPair &pair1,
|
||||
const LibertyPortPair &pair2) const
|
||||
{
|
||||
ObjectId id1 = pair1.first->id();
|
||||
ObjectId id2 = pair2.first->id();
|
||||
ObjectId id1 = pair1.first ? pair1.first->id() : 0;
|
||||
ObjectId id2 = pair2.first ? pair2.first->id() : 0;
|
||||
return id1 < id2
|
||||
|| (id1 == id2
|
||||
&& pair1.second->id() < pair2.second->id());
|
||||
|
|
|
|||
|
|
@ -281,6 +281,14 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
|||
RiseFall::fall(),
|
||||
TimingRole::nonSeqHold(),
|
||||
attrs);
|
||||
case TimingType::min_clock_tree_path:
|
||||
return makeClockTreePathArcs(cell, to_port, related_out,
|
||||
TimingRole::clockTreePathMin(),
|
||||
attrs);
|
||||
case TimingType::max_clock_tree_path:
|
||||
return makeClockTreePathArcs(cell, to_port, related_out,
|
||||
TimingRole::clockTreePathMax(),
|
||||
attrs);
|
||||
case TimingType::min_pulse_width:
|
||||
case TimingType::minimum_period:
|
||||
case TimingType::nochange_high_high:
|
||||
|
|
@ -289,8 +297,6 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
|||
case TimingType::nochange_low_low:
|
||||
case TimingType::retaining_time:
|
||||
case TimingType::unknown:
|
||||
case TimingType::min_clock_tree_path:
|
||||
case TimingType::max_clock_tree_path:
|
||||
return nullptr;
|
||||
}
|
||||
// Prevent warnings from lame compilers.
|
||||
|
|
@ -647,6 +653,23 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
|
|||
return arc_set;
|
||||
}
|
||||
|
||||
TimingArcSet *
|
||||
LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
||||
LibertyPort *to_port,
|
||||
LibertyPort *related_out,
|
||||
TimingRole *role,
|
||||
TimingArcAttrsPtr attrs)
|
||||
{
|
||||
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port,
|
||||
related_out, role, attrs);
|
||||
for (auto to_rf : RiseFall::range()) {
|
||||
TimingModel *model = attrs->model(to_rf);
|
||||
if (model)
|
||||
makeTimingArc(arc_set, nullptr, to_rf, model);
|
||||
}
|
||||
return arc_set;
|
||||
}
|
||||
|
||||
TimingArcSet *
|
||||
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
|
||||
LibertyPort *from,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ public:
|
|||
bool to_rise,
|
||||
bool to_fall,
|
||||
TimingArcAttrsPtr attrs);
|
||||
TimingArcSet *makeClockTreePathArcs(LibertyCell *cell,
|
||||
LibertyPort *to_port,
|
||||
LibertyPort *related_out,
|
||||
TimingRole *role,
|
||||
TimingArcAttrsPtr attrs);
|
||||
|
||||
protected:
|
||||
ConcretePort *makeBusPort(const char *name,
|
||||
|
|
|
|||
|
|
@ -2195,6 +2195,8 @@ LibertyReader::makeTimingArcs(LibertyPort *to_port,
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
makeTimingArcs(to_port, related_out_port, timing);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2363,6 +2365,26 @@ LibertyReader::makeTimingArcs(const char *from_port_name,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::makeTimingArcs(LibertyPort *to_port,
|
||||
LibertyPort *related_out_port,
|
||||
TimingGroup *timing)
|
||||
{
|
||||
if (to_port->hasMembers()) {
|
||||
LibertyPortMemberIterator bit_iter(to_port);
|
||||
while (bit_iter.hasNext()) {
|
||||
LibertyPort *to_port_bit = bit_iter.next();
|
||||
builder_.makeTimingArcs(cell_, nullptr, to_port_bit,
|
||||
related_out_port, timing->attrs(),
|
||||
timing->line());
|
||||
}
|
||||
}
|
||||
else
|
||||
builder_.makeTimingArcs(cell_, nullptr, to_port,
|
||||
related_out_port, timing->attrs(),
|
||||
timing->line());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -178,6 +178,9 @@ public:
|
|||
LibertyPort *to_port,
|
||||
LibertyPort *related_out_port,
|
||||
TimingGroup *timing);
|
||||
virtual void makeTimingArcs(LibertyPort *to_port,
|
||||
LibertyPort *related_out_port,
|
||||
TimingGroup *timing);
|
||||
|
||||
virtual void visitClockGatingIntegratedCell(LibertyAttr *attr);
|
||||
virtual void visitArea(LibertyAttr *attr);
|
||||
|
|
|
|||
|
|
@ -364,7 +364,8 @@ void
|
|||
LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set)
|
||||
{
|
||||
fprintf(stream_, " timing() {\n");
|
||||
fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name());
|
||||
if (arc_set->from())
|
||||
fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name());
|
||||
TimingSense sense = arc_set->sense();
|
||||
if (sense != TimingSense::unknown
|
||||
&& sense != TimingSense::non_unate)
|
||||
|
|
@ -398,11 +399,14 @@ LibertyWriter::writeTimingModels(const TimingArc *arc,
|
|||
fprintf(stream_, " }\n");
|
||||
|
||||
const TableModel *slew_model = gate_model->slewModel();
|
||||
template_name = slew_model->tblTemplate()->name();
|
||||
fprintf(stream_, " %s_transition(%s) {\n", rf->name(), template_name);
|
||||
writeTableModel(slew_model);
|
||||
fprintf(stream_, " }\n");
|
||||
} else if (check_model) {
|
||||
if (slew_model) {
|
||||
template_name = slew_model->tblTemplate()->name();
|
||||
fprintf(stream_, " %s_transition(%s) {\n", rf->name(), template_name);
|
||||
writeTableModel(slew_model);
|
||||
fprintf(stream_, " }\n");
|
||||
}
|
||||
}
|
||||
else if (check_model) {
|
||||
const TableModel *model = check_model->model();
|
||||
const char *template_name = model->tblTemplate()->name();
|
||||
fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name);
|
||||
|
|
@ -569,11 +573,15 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set)
|
|||
else
|
||||
return "non_seq_hold_falling";
|
||||
}
|
||||
else if (role == TimingRole::clockTreePathMin())
|
||||
return "min_clock_tree_path";
|
||||
else if (role == TimingRole::clockTreePathMax())
|
||||
return "max_clock_tree_path";
|
||||
else {
|
||||
report_->error(703, "%s/%s/%s timing arc type %s not supported.",
|
||||
library_->name(),
|
||||
arc_set->from()->libertyCell()->name(),
|
||||
arc_set->from()->name(),
|
||||
arc_set->to()->libertyCell()->name(),
|
||||
arc_set->to()->name(),
|
||||
role->asString());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ CheckTableModel::checkAxis(TableAxisPtr axis)
|
|||
TableModel::TableModel(TablePtr table,
|
||||
TableTemplate *tbl_template,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf) :
|
||||
const RiseFall *rf) :
|
||||
table_(table),
|
||||
tbl_template_(tbl_template),
|
||||
scale_factor_type_(int(scale_factor_type)),
|
||||
|
|
|
|||
|
|
@ -127,13 +127,13 @@ TimingArcAttrs::setModeValue(const char *value)
|
|||
}
|
||||
|
||||
TimingModel *
|
||||
TimingArcAttrs::model(RiseFall *rf) const
|
||||
TimingArcAttrs::model(const RiseFall *rf) const
|
||||
{
|
||||
return models_[rf->index()];
|
||||
}
|
||||
|
||||
void
|
||||
TimingArcAttrs::setModel(RiseFall *rf,
|
||||
TimingArcAttrs::setModel(const RiseFall *rf,
|
||||
TimingModel *model)
|
||||
{
|
||||
models_[rf->index()] = model;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ TimingRole *TimingRole::data_check_setup_;
|
|||
TimingRole *TimingRole::data_check_hold_;
|
||||
TimingRole *TimingRole::non_seq_setup_;
|
||||
TimingRole *TimingRole::non_seq_hold_;
|
||||
TimingRole *TimingRole::clock_tree_path_min_;
|
||||
TimingRole *TimingRole::clock_tree_path_max_;
|
||||
|
||||
TimingRoleMap TimingRole::timing_roles_;
|
||||
|
||||
|
|
@ -111,6 +113,10 @@ TimingRole::init()
|
|||
MinMax::max(), TimingRole::setup(), 25);
|
||||
non_seq_hold_ = new TimingRole("non-sequential hold", false, true, true,
|
||||
MinMax::min(), TimingRole::hold(), 26);
|
||||
clock_tree_path_min_ = new TimingRole("min clock tree path", false, false, false,
|
||||
MinMax::min(), nullptr, 27);
|
||||
clock_tree_path_max_ = new TimingRole("max clock tree path", false, false, false,
|
||||
MinMax::max(), nullptr, 28);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -358,4 +358,29 @@ ClkSkews::findFanout(Vertex *from)
|
|||
return endpoints;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
ClkSkews::findClkDelays(const Clock *clk,
|
||||
// Return values.
|
||||
ClkDelays &delays)
|
||||
{
|
||||
for (Vertex *clk_vertex : *graph_->regClkVertices()) {
|
||||
VertexPathIterator path_iter(clk_vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
PathVertex *path = path_iter.next();
|
||||
const ClockEdge *path_clk_edge = path->clkEdge(this);
|
||||
const RiseFall *clk_rf = path_clk_edge->transition();
|
||||
const Clock *path_clk = path_clk_edge->clock();
|
||||
if (path_clk == clk) {
|
||||
Arrival arrival = path->arrival(this);
|
||||
Delay clk_delay = delayAsFloat(arrival) - path_clk_edge->time();
|
||||
const MinMax *min_max = path->minMax(this);
|
||||
const RiseFall *rf = path->transition(this);
|
||||
delays[clk_rf->index()][rf->index()].setValue(min_max, clk_delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "Map.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Transition.hh"
|
||||
#include "SearchClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
@ -27,7 +28,7 @@ class ClkSkew;
|
|||
|
||||
typedef Map<const Clock*, ClkSkew*> ClkSkewMap;
|
||||
|
||||
// Find and report min clock skews.
|
||||
// Find and report clock skews between source/target registers.
|
||||
class ClkSkews : public StaState
|
||||
{
|
||||
public:
|
||||
|
|
@ -37,10 +38,13 @@ public:
|
|||
const Corner *corner,
|
||||
const SetupHold *setup_hold,
|
||||
int digits);
|
||||
// Find worst clock skew.
|
||||
// Find worst clock skew between src/target registers.
|
||||
float findWorstClkSkew(const Corner *corner,
|
||||
const SetupHold *setup_hold);
|
||||
|
||||
void findClkDelays(const Clock *clk,
|
||||
// Return values.
|
||||
ClkDelays &delays);
|
||||
|
||||
protected:
|
||||
void findClkSkew(ClockSet *clks,
|
||||
const Corner *corner,
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@
|
|||
#include "Sta.hh"
|
||||
#include "VisitPathEnds.hh"
|
||||
#include "ArcDelayCalc.hh"
|
||||
#include "ClkSkew.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::make_shared;
|
||||
|
||||
|
|
@ -96,6 +98,7 @@ MakeTimingModel::makeTimingModel()
|
|||
|
||||
findTimingFromInputs();
|
||||
findClkedOutputPaths();
|
||||
findClkInsertionDelays();
|
||||
|
||||
cell_->finish(false, report_, debug_);
|
||||
restoreSdc();
|
||||
|
|
@ -505,6 +508,63 @@ MakeTimingModel::findClkedOutputPaths()
|
|||
delete output_iter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
MakeTimingModel::findClkInsertionDelays()
|
||||
{
|
||||
Instance *top_inst = network_->topInstance();
|
||||
Cell *top_cell = network_->cell(top_inst);
|
||||
CellPortIterator *port_iter = network_->portIterator(top_cell);
|
||||
while (port_iter->hasNext()) {
|
||||
Port *port = port_iter->next();
|
||||
if (network_->direction(port)->isInput()) {
|
||||
const char *port_name = network_->name(port);
|
||||
LibertyPort *lib_port = cell_->findLibertyPort(port_name);
|
||||
Pin *pin = network_->findPin(top_inst, port);
|
||||
if (sdc_->isClock(pin)) {
|
||||
lib_port->setIsClock(true);
|
||||
ClockSet *clks = sdc_->findClocks(pin);
|
||||
size_t clk_count = clks->size();
|
||||
if (clk_count == 1) {
|
||||
for (const Clock *clk : *clks) {
|
||||
TimingArcAttrsPtr attrs = nullptr;
|
||||
ClkDelays delays;
|
||||
sta_->findClkDelays(clk, delays);
|
||||
for (const MinMax *min_max : MinMax::range()) {
|
||||
for (const RiseFall *clk_rf : RiseFall::range()) {
|
||||
int clk_rf_index = clk_rf->index();
|
||||
float delay = min_max->initValue();
|
||||
for (const int end_rf_index : RiseFall::rangeIndex()) {
|
||||
float delay1;
|
||||
bool exists;
|
||||
delays[clk_rf_index][end_rf_index].value(min_max, delay1, exists);
|
||||
if (exists)
|
||||
delay = min_max->minMax(delay, delay1);
|
||||
}
|
||||
TimingModel *model = makeGateModelScalar(delay, clk_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = std::make_shared<TimingArcAttrs>();
|
||||
attrs->setModel(clk_rf, model);
|
||||
}
|
||||
if (attrs)
|
||||
attrs->setTimingSense(TimingSense::positive_unate);
|
||||
TimingRole *role = (min_max == MinMax::min())
|
||||
? TimingRole::clockTreePathMin()
|
||||
: TimingRole::clockTreePathMax();
|
||||
lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr,
|
||||
role, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete port_iter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
LibertyPort *
|
||||
MakeTimingModel::modelPort(const Pin *pin)
|
||||
{
|
||||
|
|
@ -514,7 +574,7 @@ MakeTimingModel::modelPort(const Pin *pin)
|
|||
TimingModel *
|
||||
MakeTimingModel::makeScalarCheckModel(float value,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf)
|
||||
const RiseFall *rf)
|
||||
{
|
||||
TablePtr table = make_shared<Table0>(value);
|
||||
TableTemplate *tbl_template =
|
||||
|
|
@ -528,7 +588,7 @@ MakeTimingModel::makeScalarCheckModel(float value,
|
|||
TimingModel *
|
||||
MakeTimingModel::makeGateModelScalar(Delay delay,
|
||||
Slew slew,
|
||||
RiseFall *rf)
|
||||
const RiseFall *rf)
|
||||
{
|
||||
TablePtr delay_table = make_shared<Table0>(delayAsFloat(delay));
|
||||
TablePtr slew_table = make_shared<Table0>(delayAsFloat(slew));
|
||||
|
|
@ -544,12 +604,27 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
|
|||
return gate_model;
|
||||
}
|
||||
|
||||
TimingModel *
|
||||
MakeTimingModel::makeGateModelScalar(Delay delay,
|
||||
const RiseFall *rf)
|
||||
{
|
||||
TablePtr delay_table = make_shared<Table0>(delayAsFloat(delay));
|
||||
TableTemplate *tbl_template =
|
||||
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
||||
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
||||
ScaleFactorType::cell, rf);
|
||||
GateTableModel *gate_model = new GateTableModel(delay_model, nullptr,
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
return gate_model;
|
||||
}
|
||||
|
||||
// Eval the driver pin model along its load capacitance
|
||||
// axis and add the input to output 'delay' to the table values.
|
||||
TimingModel *
|
||||
MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
||||
Delay delay,
|
||||
RiseFall *rf)
|
||||
const RiseFall *rf)
|
||||
{
|
||||
const DcalcAnalysisPt *dcalc_ap = corner_->findDcalcAnalysisPt(min_max_);
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ private:
|
|||
void findTimingFromInputs();
|
||||
void findTimingFromInput(Port *input_port);
|
||||
void findClkedOutputPaths();
|
||||
void findClkInsertionDelays();
|
||||
void findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
|
|
@ -70,13 +71,15 @@ private:
|
|||
OutputPinDelays &output_pin_delays);
|
||||
TimingModel *makeScalarCheckModel(float value,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf);
|
||||
const RiseFall *rf);
|
||||
TimingModel *makeGateModelScalar(Delay delay,
|
||||
Slew slew,
|
||||
RiseFall *rf);
|
||||
const RiseFall *rf);
|
||||
TimingModel *makeGateModelScalar(Delay delay,
|
||||
const RiseFall *rf);
|
||||
TimingModel *makeGateModelTable(const Pin *output_pin,
|
||||
Delay delay,
|
||||
RiseFall *rf);
|
||||
const RiseFall *rf);
|
||||
TableTemplate *ensureTableTemplate(const TableTemplate *drvr_template,
|
||||
TableAxisPtr load_axis);
|
||||
TableAxisPtr loadCapacitanceAxis(const TableModel *table);
|
||||
|
|
|
|||
|
|
@ -2617,6 +2617,15 @@ Sta::findWorstClkSkew(const SetupHold *setup_hold)
|
|||
return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::findClkDelays(const Clock *clk,
|
||||
// Return values.
|
||||
ClkDelays &delays)
|
||||
{
|
||||
clkSkewPreamble();
|
||||
clk_skews_->findClkDelays(clk, delays);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::clkSkewPreamble()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue