write_timing_model input->output arcs
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
706660a503
commit
2b498c93c4
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -54,6 +54,9 @@ public:
|
|||
void mergeValue(const RiseFallBoth *rf,
|
||||
const MinMaxAll *min_max,
|
||||
float value);
|
||||
void mergeValue(const RiseFall *rf,
|
||||
const MinMax *min_max,
|
||||
float value);
|
||||
void setValues(RiseFallMinMax *values);
|
||||
void removeValue(const RiseFallBoth *rf,
|
||||
const MinMax *min_max);
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ public:
|
|||
void removeClockGroupsAsynchronous(const char *name);
|
||||
bool sameClockGroup(const Clock *clk1,
|
||||
const Clock *clk2);
|
||||
// Clocks explicitly excluded by set_clock_group.
|
||||
// Clocks explicitly excluded by set_clock_group.
|
||||
bool sameClockGroupExplicit(const Clock *clk1,
|
||||
const Clock *clk2);
|
||||
ClockGroupIterator *clockGroupIterator();
|
||||
|
|
@ -531,7 +531,7 @@ public:
|
|||
const MinMaxAll *min_max,
|
||||
bool add, float delay);
|
||||
void removeInputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ public:
|
|||
RiseFall *from_rf,
|
||||
TimingRole *role,
|
||||
TimingArcAttrs *attrs);
|
||||
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *to_port,
|
||||
LibertyPort *related_out,
|
||||
bool to_rise,
|
||||
bool to_fall,
|
||||
TimingArcAttrs *attrs);
|
||||
|
||||
protected:
|
||||
ConcretePort *makeBusPort(const char *name,
|
||||
|
|
@ -102,13 +109,6 @@ protected:
|
|||
RiseFall *from_rf,
|
||||
RiseFall *to_rf,
|
||||
TimingModel *model);
|
||||
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *to_port,
|
||||
LibertyPort *related_out,
|
||||
bool to_rise,
|
||||
bool to_fall,
|
||||
TimingArcAttrs *attrs);
|
||||
TimingArcSet *makeLatchDtoQArcs(LibertyCell *cell,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *to_port,
|
||||
|
|
|
|||
|
|
@ -106,6 +106,20 @@ RiseFallMinMax::mergeValue(const RiseFallBoth *rf,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RiseFallMinMax::mergeValue(const RiseFall *rf,
|
||||
const MinMax *min_max,
|
||||
float value)
|
||||
{
|
||||
int rf_index = rf->index();
|
||||
int mm_index = min_max->index();
|
||||
if (!exists_[rf_index][mm_index]
|
||||
|| min_max->compare(value, values_[rf_index][mm_index])) {
|
||||
values_[rf_index][mm_index] = value;
|
||||
exists_[rf_index][mm_index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RiseFallMinMax::setValue(const RiseFallBoth *rf,
|
||||
const MinMax *min_max,
|
||||
|
|
|
|||
|
|
@ -2721,7 +2721,7 @@ Sdc::findInputDelay(const Pin *pin,
|
|||
|
||||
void
|
||||
Sdc::removeInputDelay(Pin *pin,
|
||||
RiseFallBoth *rf,
|
||||
const RiseFallBoth *rf,
|
||||
Clock *clk,
|
||||
RiseFall *clk_rf,
|
||||
MinMaxAll *min_max)
|
||||
|
|
|
|||
|
|
@ -66,12 +66,10 @@ MakeTimingModel::makeTimingModel(const char *cell_name,
|
|||
for (Clock *clk : *sdc_->clocks())
|
||||
sta_->setPropagatedClock(clk);
|
||||
|
||||
#if 0
|
||||
//findInputToOutputPaths();
|
||||
findInputSetupHolds();
|
||||
#endif
|
||||
sta_->searchPreamble();
|
||||
findInputSetupHolds();
|
||||
graph_ = sta_->graph();
|
||||
|
||||
findTimingFromInputs();
|
||||
findClkedOutputPaths();
|
||||
|
||||
cell_->finish(false, report_, debug_);
|
||||
|
|
@ -153,52 +151,6 @@ MakeTimingModel::makePorts()
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// input -> output combinational paths
|
||||
// too slow to use
|
||||
void
|
||||
MakeTimingModel::findInputToOutputPaths()
|
||||
{
|
||||
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)) {
|
||||
InstancePinIterator *output_iter = network_->pinIterator(network_->topInstance());
|
||||
while (output_iter->hasNext()) {
|
||||
Pin *output_pin = output_iter->next();
|
||||
if (network_->direction(output_pin)->isOutput()) {
|
||||
PinSet *from_pins = new PinSet;
|
||||
from_pins->insert(input_pin);
|
||||
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
||||
RiseFallBoth::riseFall());
|
||||
PinSet *to_pins = new PinSet;
|
||||
to_pins->insert(output_pin);
|
||||
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
||||
RiseFallBoth::riseFall(),
|
||||
RiseFallBoth::riseFall());
|
||||
PathEndSeq *ends = sta_->findPathEnds(from, nullptr, to, true, corner_,
|
||||
min_max_->asMinMaxAll(),
|
||||
1, 1, false,
|
||||
-INF, INF, false, nullptr,
|
||||
false, false, false, false, false, false);
|
||||
if (!ends->empty()) {
|
||||
debugPrint(debug_, "make_timing_model", 1, "input %s -> output %s",
|
||||
network_->pathName(input_pin),
|
||||
network_->pathName(output_pin));
|
||||
PathEnd *end = (*ends)[0];
|
||||
if (debug_->check("make_timing_model", 2))
|
||||
sta_->reportPathEnd(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef std::map<ClockEdge*, RiseFallMinMax> ClockMargins;
|
||||
|
||||
class MakeEndTimingArcs : public PathEndVisitor
|
||||
{
|
||||
public:
|
||||
|
|
@ -248,12 +200,12 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
|||
ClockEdge *tgt_clk_edge = path_end->targetClkEdge(sta_);
|
||||
Debug *debug = sta_->debug();
|
||||
const MinMax *min_max = path_end->minMax(sta_);
|
||||
debugPrint(debug, "make_timing_model", 2, "%s %s %s %s -> clock %s",
|
||||
path_end->typeName(),
|
||||
min_max->asString(),
|
||||
debugPrint(debug, "make_timing_model", 2, "%s %s -> clock %s %s %s",
|
||||
sta_->network()->pathName(input_pin_),
|
||||
input_rf_->shortName(),
|
||||
tgt_clk_edge->name());
|
||||
tgt_clk_edge->name(),
|
||||
path_end->typeName(),
|
||||
min_max->asString());
|
||||
if (debug->check("make_timing_model", 3))
|
||||
sta_->reportPathEnd(path_end);
|
||||
Arrival data_arrival = path_end->path()->arrival(sta_);
|
||||
|
|
@ -265,20 +217,21 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
|||
}
|
||||
|
||||
// input -> register setup/hold
|
||||
// input -> output combinational paths
|
||||
// Use default input arrival (set_input_delay with no clock) from inputs
|
||||
// to find downstream register checks and output ports.
|
||||
void
|
||||
MakeTimingModel::findInputSetupHolds()
|
||||
MakeTimingModel::findTimingFromInputs()
|
||||
{
|
||||
Debug *debug = sta_->debug();
|
||||
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();
|
||||
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,
|
||||
|
|
@ -296,57 +249,128 @@ MakeTimingModel::findInputSetupHolds()
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ClockMargins &clk_margins = end_visitor.margins();
|
||||
for (auto clk_edge_margins : clk_margins) {
|
||||
ClockEdge *clk_edge = clk_edge_margins.first;
|
||||
RiseFallMinMax &margins = clk_edge_margins.second;
|
||||
for (MinMax *min_max : MinMax::range()) {
|
||||
bool setup = (min_max == MinMax::max());
|
||||
TimingArcAttrs *attrs = nullptr;
|
||||
for (RiseFall *input_rf : RiseFall::range()) {
|
||||
float margin;
|
||||
bool exists;
|
||||
margins.value(input_rf, min_max, margin, exists);
|
||||
if (exists) {
|
||||
debugPrint(debug, "make_timing_model", 1, "%s %s %s -> clock %s %s",
|
||||
sta_->network()->pathName(input_pin),
|
||||
input_rf->shortName(),
|
||||
min_max == MinMax::max() ? "setup" : "hold",
|
||||
clk_edge->name(),
|
||||
delayAsString(margin, sta_));
|
||||
ScaleFactorType scale_type = setup
|
||||
? ScaleFactorType::setup
|
||||
: ScaleFactorType::hold;
|
||||
TimingModel *check_model = makeScalarCheckModel(margin, scale_type, input_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = new TimingArcAttrs();
|
||||
attrs->setModel(input_rf, check_model);
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
LibertyPort *input_port = modelPort(input_pin);
|
||||
for (const Pin *clk_pin : clk_edge->clock()->pins()) {
|
||||
LibertyPort *clk_port = modelPort(clk_pin);
|
||||
RiseFall *clk_rf = clk_edge->transition();
|
||||
TimingRole *role = setup ? TimingRole::setup() : TimingRole::hold();
|
||||
lib_builder_->makeFromTransitionArcs(cell_, clk_port,
|
||||
input_port, nullptr,
|
||||
clk_rf, role, attrs);
|
||||
}
|
||||
}
|
||||
void
|
||||
MakeTimingModel::findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays)
|
||||
{
|
||||
InstancePinIterator *output_iter = network_->pinIterator(network_->topInstance());
|
||||
while (output_iter->hasNext()) {
|
||||
Pin *output_pin = output_iter->next();
|
||||
if (network_->direction(output_pin)->isOutput()) {
|
||||
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
||||
VertexPathIterator path_iter(output_vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
PathVertex *path = path_iter.next();
|
||||
if (search_->matchesFilter(path, nullptr)) {
|
||||
const RiseFall *output_rf = path->transition(sta_);
|
||||
const MinMax *min_max = path->minMax(sta_);
|
||||
Arrival delay = path->arrival(sta_);
|
||||
OutputDelays &delays = output_pin_delays[output_pin];
|
||||
delays.delays.mergeValue(output_rf, min_max, delay);
|
||||
delays.rf_path_exists[input_rf->index()][output_rf->index()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
const ClockMargins &clk_margins)
|
||||
{
|
||||
for (auto clk_edge_margins : clk_margins) {
|
||||
ClockEdge *clk_edge = clk_edge_margins.first;
|
||||
RiseFallMinMax &margins = clk_edge_margins.second;
|
||||
for (MinMax *min_max : MinMax::range()) {
|
||||
bool setup = (min_max == MinMax::max());
|
||||
TimingArcAttrs *attrs = nullptr;
|
||||
for (RiseFall *input_rf : RiseFall::range()) {
|
||||
float margin;
|
||||
bool exists;
|
||||
margins.value(input_rf, min_max, margin, exists);
|
||||
if (exists) {
|
||||
debugPrint(debug_, "make_timing_model", 2, "%s %s %s -> clock %s %s",
|
||||
sta_->network()->pathName(input_pin),
|
||||
input_rf->shortName(),
|
||||
min_max == MinMax::max() ? "setup" : "hold",
|
||||
clk_edge->name(),
|
||||
delayAsString(margin, sta_));
|
||||
ScaleFactorType scale_type = setup
|
||||
? ScaleFactorType::setup
|
||||
: ScaleFactorType::hold;
|
||||
TimingModel *check_model = makeScalarCheckModel(margin, scale_type, input_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = new TimingArcAttrs();
|
||||
attrs->setModel(input_rf, check_model);
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
LibertyPort *input_port = modelPort(input_pin);
|
||||
for (const Pin *clk_pin : clk_edge->clock()->pins()) {
|
||||
LibertyPort *clk_port = modelPort(clk_pin);
|
||||
RiseFall *clk_rf = clk_edge->transition();
|
||||
TimingRole *role = setup ? TimingRole::setup() : TimingRole::hold();
|
||||
lib_builder_->makeFromTransitionArcs(cell_, clk_port,
|
||||
input_port, nullptr,
|
||||
clk_rf, role, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin,
|
||||
OutputPinDelays &output_pin_delays)
|
||||
{
|
||||
const DcalcAnalysisPt *dcalc_ap = corner_->findDcalcAnalysisPt(min_max_);
|
||||
for (auto out_pin_delay : output_pin_delays) {
|
||||
const Pin *output_pin = out_pin_delay.first;
|
||||
OutputDelays &output_delays = out_pin_delay.second;
|
||||
TimingArcAttrs *attrs = nullptr;
|
||||
for (RiseFall *output_rf : RiseFall::range()) {
|
||||
MinMax *min_max = MinMax::max();
|
||||
float delay;
|
||||
bool exists;
|
||||
output_delays.delays.value(output_rf, min_max, delay, exists);
|
||||
if (exists) {
|
||||
debugPrint(debug_, "make_timing_model", 2, "%s -> %s %s delay %s",
|
||||
network_->pathName(input_pin),
|
||||
network_->pathName(output_pin),
|
||||
output_rf->shortName(),
|
||||
delayAsString(delay, sta_));
|
||||
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
||||
Slew slew = graph_->slew(output_vertex, output_rf, dcalc_ap->index());
|
||||
TimingModel *gate_model = makeScalarGateModel(delay, slew, output_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = new TimingArcAttrs();
|
||||
attrs->setModel(output_rf, gate_model);
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
LibertyPort *output_port = modelPort(output_pin);
|
||||
LibertyPort *input_port = modelPort(input_pin);
|
||||
attrs->setTimingSense(output_delays.timingSense());
|
||||
lib_builder_->makeCombinationalArcs(cell_, input_port,
|
||||
output_port, nullptr,
|
||||
true, true, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Rewrite to use non-filtered arrivals at outputs from each clock.
|
||||
|
|
@ -387,14 +411,14 @@ MakeTimingModel::findClkedOutputPaths()
|
|||
clk->name(),
|
||||
network_->pathName(output_pin));
|
||||
PathEnd *end = (*ends)[0];
|
||||
if (debug_->check("make_timing_model", 2))
|
||||
if (debug_->check("make_timing_model", 3))
|
||||
sta_->reportPathEnd(end);
|
||||
Arrival delay = end->path()->arrival(sta_);
|
||||
Slew slew = end->path()->slew(sta_);
|
||||
TimingModel *check_model = makeScalarGateModel(delay, slew, output_rf);
|
||||
TimingModel *gate_model = makeScalarGateModel(delay, slew, output_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = new TimingArcAttrs();
|
||||
attrs->setModel(output_rf, check_model);
|
||||
attrs->setModel(output_rf, gate_model);
|
||||
}
|
||||
sta_->removeOutputDelay(output_pin, output_rf1, clk, clk_rf, MinMaxAll::max());
|
||||
}
|
||||
|
|
@ -448,4 +472,39 @@ MakeTimingModel::makeScalarGateModel(Delay delay,
|
|||
return gate_model;
|
||||
}
|
||||
|
||||
OutputDelays::OutputDelays()
|
||||
{
|
||||
rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()] = false;
|
||||
rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()] = false;
|
||||
rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()] = false;
|
||||
rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()] = false;
|
||||
}
|
||||
|
||||
TimingSense
|
||||
OutputDelays::timingSense() const
|
||||
{
|
||||
if (rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()]
|
||||
&& rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()]
|
||||
&& rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()]
|
||||
&& rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()])
|
||||
return TimingSense::non_unate;
|
||||
else if (rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()]
|
||||
&& rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()]
|
||||
&& !rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()]
|
||||
&& !rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()])
|
||||
return TimingSense::positive_unate;
|
||||
else if (rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()]
|
||||
&& rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()]
|
||||
&& !rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()]
|
||||
&& !rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()])
|
||||
return TimingSense::negative_unate;
|
||||
else if (rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()]
|
||||
|| rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()]
|
||||
|| rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()]
|
||||
|| rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()])
|
||||
return TimingSense::non_unate;
|
||||
else
|
||||
return TimingSense::none;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -16,15 +16,32 @@
|
|||
|
||||
#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;
|
||||
bool rf_path_exists[RiseFall::index_count][RiseFall::index_count];
|
||||
};
|
||||
|
||||
typedef std::map<ClockEdge*, RiseFallMinMax> ClockMargins;
|
||||
typedef std::map<const Pin *, OutputDelays> OutputPinDelays;
|
||||
|
||||
class MakeTimingModel : public StaState
|
||||
{
|
||||
public:
|
||||
|
|
@ -40,17 +57,21 @@ private:
|
|||
void makeCell(const char *cell_name,
|
||||
const char *filename);
|
||||
void makePorts();
|
||||
void findInputToOutputPaths();
|
||||
void findInputSetupHolds();
|
||||
void findTimingFromInputs();
|
||||
void findClkedOutputPaths();
|
||||
|
||||
LibertyPort *modelPort(const Pin *pin);
|
||||
void findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
const ClockMargins &clk_margins);
|
||||
void makeInputOutputTimingArcs(const Pin *input_pin,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
TimingModel *makeScalarCheckModel(float value,
|
||||
ScaleFactorType scale_factor_type,
|
||||
RiseFall *rf);
|
||||
TimingModel *makeScalarGateModel(Delay delay,
|
||||
Slew slew,
|
||||
RiseFall *rf);
|
||||
LibertyPort *modelPort(const Pin *pin);
|
||||
|
||||
Sta *sta_;
|
||||
LibertyLibrary *library_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue