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

View File

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

View File

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

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

View File

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

View File

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

View File

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