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,
|
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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue