write_timing_model input->output arcs

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2022-06-10 16:26:14 -07:00
parent 706660a503
commit 2b498c93c4
8 changed files with 210 additions and 113 deletions

Binary file not shown.

View File

@ -54,6 +54,9 @@ public:
void mergeValue(const RiseFallBoth *rf, void mergeValue(const RiseFallBoth *rf,
const MinMaxAll *min_max, const MinMaxAll *min_max,
float value); float value);
void mergeValue(const RiseFall *rf,
const MinMax *min_max,
float value);
void setValues(RiseFallMinMax *values); void setValues(RiseFallMinMax *values);
void removeValue(const RiseFallBoth *rf, void removeValue(const RiseFallBoth *rf,
const MinMax *min_max); const MinMax *min_max);

View File

@ -475,7 +475,7 @@ public:
void removeClockGroupsAsynchronous(const char *name); void removeClockGroupsAsynchronous(const char *name);
bool sameClockGroup(const Clock *clk1, bool sameClockGroup(const Clock *clk1,
const Clock *clk2); const Clock *clk2);
// Clocks explicitly excluded by set_clock_group. // Clocks explicitly excluded by set_clock_group.
bool sameClockGroupExplicit(const Clock *clk1, bool sameClockGroupExplicit(const Clock *clk1,
const Clock *clk2); const Clock *clk2);
ClockGroupIterator *clockGroupIterator(); ClockGroupIterator *clockGroupIterator();
@ -531,7 +531,7 @@ public:
const MinMaxAll *min_max, const MinMaxAll *min_max,
bool add, float delay); bool add, float delay);
void removeInputDelay(Pin *pin, void removeInputDelay(Pin *pin,
RiseFallBoth *rf, const RiseFallBoth *rf,
Clock *clk, Clock *clk,
RiseFall *clk_rf, RiseFall *clk_rf,
MinMaxAll *min_max); MinMaxAll *min_max);

View File

@ -67,6 +67,13 @@ public:
RiseFall *from_rf, RiseFall *from_rf,
TimingRole *role, TimingRole *role,
TimingArcAttrs *attrs); TimingArcAttrs *attrs);
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs);
protected: protected:
ConcretePort *makeBusPort(const char *name, ConcretePort *makeBusPort(const char *name,
@ -102,13 +109,6 @@ protected:
RiseFall *from_rf, RiseFall *from_rf,
RiseFall *to_rf, RiseFall *to_rf,
TimingModel *model); 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, TimingArcSet *makeLatchDtoQArcs(LibertyCell *cell,
LibertyPort *from_port, LibertyPort *from_port,
LibertyPort *to_port, LibertyPort *to_port,

View File

@ -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 void
RiseFallMinMax::setValue(const RiseFallBoth *rf, RiseFallMinMax::setValue(const RiseFallBoth *rf,
const MinMax *min_max, const MinMax *min_max,

View File

@ -2721,7 +2721,7 @@ Sdc::findInputDelay(const Pin *pin,
void void
Sdc::removeInputDelay(Pin *pin, Sdc::removeInputDelay(Pin *pin,
RiseFallBoth *rf, const RiseFallBoth *rf,
Clock *clk, Clock *clk,
RiseFall *clk_rf, RiseFall *clk_rf,
MinMaxAll *min_max) MinMaxAll *min_max)

View File

@ -66,12 +66,10 @@ MakeTimingModel::makeTimingModel(const char *cell_name,
for (Clock *clk : *sdc_->clocks()) for (Clock *clk : *sdc_->clocks())
sta_->setPropagatedClock(clk); sta_->setPropagatedClock(clk);
#if 0
//findInputToOutputPaths();
findInputSetupHolds();
#endif
sta_->searchPreamble(); sta_->searchPreamble();
findInputSetupHolds(); graph_ = sta_->graph();
findTimingFromInputs();
findClkedOutputPaths(); findClkedOutputPaths();
cell_->finish(false, report_, debug_); 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 class MakeEndTimingArcs : public PathEndVisitor
{ {
public: public:
@ -248,12 +200,12 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
ClockEdge *tgt_clk_edge = path_end->targetClkEdge(sta_); ClockEdge *tgt_clk_edge = path_end->targetClkEdge(sta_);
Debug *debug = sta_->debug(); Debug *debug = sta_->debug();
const MinMax *min_max = path_end->minMax(sta_); const MinMax *min_max = path_end->minMax(sta_);
debugPrint(debug, "make_timing_model", 2, "%s %s %s %s -> clock %s", debugPrint(debug, "make_timing_model", 2, "%s %s -> clock %s %s %s",
path_end->typeName(),
min_max->asString(),
sta_->network()->pathName(input_pin_), sta_->network()->pathName(input_pin_),
input_rf_->shortName(), input_rf_->shortName(),
tgt_clk_edge->name()); tgt_clk_edge->name(),
path_end->typeName(),
min_max->asString());
if (debug->check("make_timing_model", 3)) if (debug->check("make_timing_model", 3))
sta_->reportPathEnd(path_end); sta_->reportPathEnd(path_end);
Arrival data_arrival = path_end->path()->arrival(sta_); Arrival data_arrival = path_end->path()->arrival(sta_);
@ -265,20 +217,21 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
} }
// input -> register setup/hold // input -> register setup/hold
// input -> output combinational paths
// Use default input arrival (set_input_delay with no clock) from inputs // Use default input arrival (set_input_delay with no clock) from inputs
// to find downstream register checks and output ports. // to find downstream register checks and output ports.
void void
MakeTimingModel::findInputSetupHolds() MakeTimingModel::findTimingFromInputs()
{ {
Debug *debug = sta_->debug();
VisitPathEnds visit_ends(sta_); VisitPathEnds visit_ends(sta_);
MakeEndTimingArcs end_visitor(sta_); MakeEndTimingArcs end_visitor(sta_);
InstancePinIterator *input_iter = network_->pinIterator(network_->topInstance()); InstancePinIterator *input_iter = network_->pinIterator(network_->topInstance());
while (input_iter->hasNext()) { while (input_iter->hasNext()) {
Pin *input_pin = input_iter->next(); Pin *input_pin = input_iter->next();
if (network_->direction(input_pin)->isInput() if (network_->direction(input_pin)->isInput()
&& !sta_->isClockSrc(input_pin)) { && !sta_->isClockSrc(input_pin)) {
end_visitor.setInputPin(input_pin); end_visitor.setInputPin(input_pin);
OutputPinDelays output_delays;
for (RiseFall *input_rf : RiseFall::range()) { for (RiseFall *input_rf : RiseFall::range()) {
RiseFallBoth *input_rf1 = input_rf->asRiseFallBoth(); RiseFallBoth *input_rf1 = input_rf->asRiseFallBoth();
sta_->setInputDelay(input_pin, input_rf1, sta_->setInputDelay(input_pin, input_rf1,
@ -296,57 +249,128 @@ MakeTimingModel::findInputSetupHolds()
end_visitor.setInputRf(input_rf); end_visitor.setInputRf(input_rf);
for (Vertex *end : *search_->endpoints()) for (Vertex *end : *search_->endpoints())
visit_ends.visitPathEnds(end, corner_, MinMaxAll::all(), true, &end_visitor); visit_ends.visitPathEnds(end, corner_, MinMaxAll::all(), true, &end_visitor);
findOutputDelays(input_rf, output_delays);
sta_->removeInputDelay(input_pin, input_rf1, sta_->removeInputDelay(input_pin, input_rf1,
sdc_->defaultArrivalClock(), sdc_->defaultArrivalClock(),
sdc_->defaultArrivalClockEdge()->transition(), sdc_->defaultArrivalClockEdge()->transition(),
MinMaxAll::all()); MinMaxAll::all());
} }
makeSetupHoldTimingArcs(input_pin, end_visitor.margins());
makeInputOutputTimingArcs(input_pin, output_delays);
}
}
}
const ClockMargins &clk_margins = end_visitor.margins(); void
for (auto clk_edge_margins : clk_margins) { MakeTimingModel::findOutputDelays(const RiseFall *input_rf,
ClockEdge *clk_edge = clk_edge_margins.first; OutputPinDelays &output_pin_delays)
RiseFallMinMax &margins = clk_edge_margins.second; {
for (MinMax *min_max : MinMax::range()) { InstancePinIterator *output_iter = network_->pinIterator(network_->topInstance());
bool setup = (min_max == MinMax::max()); while (output_iter->hasNext()) {
TimingArcAttrs *attrs = nullptr; Pin *output_pin = output_iter->next();
for (RiseFall *input_rf : RiseFall::range()) { if (network_->direction(output_pin)->isOutput()) {
float margin; Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
bool exists; VertexPathIterator path_iter(output_vertex, this);
margins.value(input_rf, min_max, margin, exists); while (path_iter.hasNext()) {
if (exists) { PathVertex *path = path_iter.next();
debugPrint(debug, "make_timing_model", 1, "%s %s %s -> clock %s %s", if (search_->matchesFilter(path, nullptr)) {
sta_->network()->pathName(input_pin), const RiseFall *output_rf = path->transition(sta_);
input_rf->shortName(), const MinMax *min_max = path->minMax(sta_);
min_max == MinMax::max() ? "setup" : "hold", Arrival delay = path->arrival(sta_);
clk_edge->name(), OutputDelays &delays = output_pin_delays[output_pin];
delayAsString(margin, sta_)); delays.delays.mergeValue(output_rf, min_max, delay);
ScaleFactorType scale_type = setup delays.rf_path_exists[input_rf->index()][output_rf->index()] = true;
? 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::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. // Rewrite to use non-filtered arrivals at outputs from each clock.
@ -387,14 +411,14 @@ MakeTimingModel::findClkedOutputPaths()
clk->name(), clk->name(),
network_->pathName(output_pin)); network_->pathName(output_pin));
PathEnd *end = (*ends)[0]; PathEnd *end = (*ends)[0];
if (debug_->check("make_timing_model", 2)) if (debug_->check("make_timing_model", 3))
sta_->reportPathEnd(end); sta_->reportPathEnd(end);
Arrival delay = end->path()->arrival(sta_); Arrival delay = end->path()->arrival(sta_);
Slew slew = end->path()->slew(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) if (attrs == nullptr)
attrs = new TimingArcAttrs(); 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()); sta_->removeOutputDelay(output_pin, output_rf1, clk, clk_rf, MinMaxAll::max());
} }
@ -448,4 +472,39 @@ MakeTimingModel::makeScalarGateModel(Delay delay,
return gate_model; 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 } // namespace

View File

@ -16,15 +16,32 @@
#pragma once #pragma once
#include <map>
#include "LibertyClass.hh" #include "LibertyClass.hh"
#include "SdcClass.hh"
#include "SearchClass.hh" #include "SearchClass.hh"
#include "StaState.hh" #include "StaState.hh"
#include "RiseFallMinMax.hh"
namespace sta { namespace sta {
class Sta; class Sta;
class LibertyBuilder; 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 class MakeTimingModel : public StaState
{ {
public: public:
@ -40,17 +57,21 @@ private:
void makeCell(const char *cell_name, void makeCell(const char *cell_name,
const char *filename); const char *filename);
void makePorts(); void makePorts();
void findInputToOutputPaths(); void findTimingFromInputs();
void findInputSetupHolds();
void findClkedOutputPaths(); void findClkedOutputPaths();
void findOutputDelays(const RiseFall *input_rf,
LibertyPort *modelPort(const Pin *pin); 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, TimingModel *makeScalarCheckModel(float value,
ScaleFactorType scale_factor_type, ScaleFactorType scale_factor_type,
RiseFall *rf); RiseFall *rf);
TimingModel *makeScalarGateModel(Delay delay, TimingModel *makeScalarGateModel(Delay delay,
Slew slew, Slew slew,
RiseFall *rf); RiseFall *rf);
LibertyPort *modelPort(const Pin *pin);
Sta *sta_; Sta *sta_;
LibertyLibrary *library_; LibertyLibrary *library_;