OpenSTA/sdc/WriteSdc.cc

3005 lines
75 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2019-01-01 21:26:11 +01:00
// Copyright (c) 2019, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <stdio.h>
#include <algorithm>
#include <time.h>
#include "Machine.hh"
#include "DisallowCopyAssign.hh"
#include "Report.hh"
#include "Error.hh"
#include "Units.hh"
#include "StaState.hh"
#include "PortDirection.hh"
#include "RiseFallValues.hh"
#include "Transition.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "NetworkCmp.hh"
#include "PortDelay.hh"
#include "ExceptionPath.hh"
#include "PortExtCap.hh"
#include "DisabledPorts.hh"
#include "Wireload.hh"
#include "ClockGroups.hh"
#include "ClockInsertion.hh"
#include "ClockLatency.hh"
#include "InputDrive.hh"
#include "DataCheck.hh"
#include "DeratingFactors.hh"
#include "Sdc.hh"
#include "Graph.hh"
#include "GraphCmp.hh"
#include "WriteSdc.hh"
#include "WriteSdcPvt.hh"
namespace sta {
typedef Set<ClockSense*> ClockSenseSet;
typedef Vector<ClockSense*> ClockSenseSeq;
static const char *
transRiseFallFlag(const TransRiseFall *tr);
static const char *
transRiseFallFlag(const TransRiseFallBoth *tr);
static const char *
minMaxFlag(const MinMaxAll *min_max);
static const char *
minMaxFlag(const MinMax *min_max);
static const char *
earlyLateFlag(const MinMax *early_late);
static const char *
setupHoldFlag(const MinMax *min_max);
static const char *
timingDerateTypeKeyword(TimingDerateType type);
////////////////////////////////////////////////////////////////
class WriteSdcObject
{
public:
WriteSdcObject() {}
virtual ~WriteSdcObject() {}
virtual void write() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(WriteSdcObject);
};
class WriteGetPort : public WriteSdcObject
{
public:
WriteGetPort(const Port *port,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetPort);
const Port *port_;
const WriteSdc *writer_;
};
WriteGetPort::WriteGetPort(const Port *port,
const WriteSdc *writer) :
port_(port),
writer_(writer)
{
}
void
WriteGetPort::write() const
{
writer_->writeGetPort(port_);
}
class WriteGetPinAndClkKey : public WriteSdcObject
{
public:
WriteGetPinAndClkKey(const Pin *pin,
const Clock *clk,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetPinAndClkKey);
const Pin *pin_;
const Clock *clk_;
const WriteSdc *writer_;
};
WriteGetPinAndClkKey::WriteGetPinAndClkKey(const Pin *pin,
const Clock *clk,
const WriteSdc *writer) :
pin_(pin),
clk_(clk),
writer_(writer)
{
}
void
WriteGetPinAndClkKey::write() const
{
writer_->writeClockKey(clk_);
fprintf(writer_->stream(), " ");
writer_->writeGetPin(pin_);
}
class WriteGetPin : public WriteSdcObject
{
public:
WriteGetPin(const Pin *pin,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetPin);
const Pin *pin_;
const WriteSdc *writer_;
};
WriteGetPin::WriteGetPin(const Pin *pin,
const WriteSdc *writer) :
pin_(pin),
writer_(writer)
{
}
void
WriteGetPin::write() const
{
writer_->writeGetPin(pin_);
}
class WriteGetNet : public WriteSdcObject
{
public:
WriteGetNet(const Net *net,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetNet);
const Net *net_;
const WriteSdc *writer_;
};
WriteGetNet::WriteGetNet(const Net *net,
const WriteSdc *writer) :
net_(net),
writer_(writer)
{
}
void
WriteGetNet::write() const
{
writer_->writeGetNet(net_);
}
class WriteGetInstance : public WriteSdcObject
{
public:
WriteGetInstance(const Instance *inst,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetInstance);
const Instance *inst_;
const WriteSdc *writer_;
};
WriteGetInstance::WriteGetInstance(const Instance *inst,
const WriteSdc *writer) :
inst_(inst),
writer_(writer)
{
}
void
WriteGetInstance::write() const
{
writer_->writeGetInstance(inst_);
}
class WriteGetLibCell : public WriteSdcObject
{
public:
WriteGetLibCell(const LibertyCell *cell,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetLibCell);
const LibertyCell *cell_;
const WriteSdc *writer_;
};
WriteGetLibCell::WriteGetLibCell(const LibertyCell *cell,
const WriteSdc *writer) :
cell_(cell),
writer_(writer)
{
}
void
WriteGetLibCell::write() const
{
writer_->writeGetLibCell(cell_);
}
class WriteGetClock : public WriteSdcObject
{
public:
WriteGetClock(const Clock *clk,
const WriteSdc *writer);
virtual void write() const;
private:
DISALLOW_COPY_AND_ASSIGN(WriteGetClock);
const Clock *clk_;
const WriteSdc *writer_;
};
WriteGetClock::WriteGetClock(const Clock *clk,
const WriteSdc *writer) :
clk_(clk),
writer_(writer)
{
}
void
WriteGetClock::write() const
{
writer_->writeGetClock(clk_);
}
////////////////////////////////////////////////////////////////
void
writeSdc(Instance *instance,
const char *filename,
const char *creator,
bool native,
bool no_timestamp,
int digits,
Sdc *sdc)
{
WriteSdc writer(instance, filename, creator, native, digits,
no_timestamp, sdc);
writer.write();
}
WriteSdc::WriteSdc(Instance *instance,
const char *filename,
const char *creator,
bool native,
int digits,
bool no_timestamp,
Sdc *sdc) :
StaState(sdc),
instance_(instance),
filename_(filename),
creator_(creator),
native_( native),
digits_(digits),
no_timestamp_(no_timestamp),
top_instance_(instance == sdc_network_->topInstance()),
instance_name_length_(strlen(sdc_network_->pathName(instance))),
cell_(sdc_network_->cell(instance))
{
}
WriteSdc::~WriteSdc()
{
}
void
WriteSdc::write()
{
openFile(filename_);
writeHeader();
writeTiming();
writeEnvironment();
writeDesignRules();
writeVariables();
closeFile();
}
void
WriteSdc::openFile(const char *filename)
{
stream_ = fopen(filename, "w");
if (stream_ == NULL)
throw FileNotWritable(filename);
}
void
WriteSdc::closeFile()
{
fclose(stream_);
}
void
WriteSdc::flush()
{
fflush(stream_);
}
void
WriteSdc::writeHeader() const
{
writeCommentSeparator();
fprintf(stream_, "# Created by %s\n", creator_);
if (!no_timestamp_) {
time_t now;
time(&now);
char *time_str = ctime(&now);
// Remove trailing \n.
time_str[strlen(time_str) - 1] = '\0';
fprintf(stream_, "# %s\n", time_str);
}
writeCommentSeparator();
fprintf(stream_, "current_design %s\n", sdc_network_->name(cell_));
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeTiming() const
{
writeCommentSection("Timing Constraints");
writeClocks();
writePropagatedClkPins();
writeClockUncertaintyPins();
writeClockLatencies();
writeClockInsertions();
writeInterClockUncertainties();
writeClockSenses();
writeClockGroups();
writeInputDelays();
writeOutputDelays();
writeDisables();
writeExceptions();
writeDataChecks();
}
void
WriteSdc::writeClocks() const
{
// Write clocks in the order they were defined because generated
// clocks depend on master clocks having been previously defined.
ClockIterator *clk_iter = sdc_->clockIterator();
while (clk_iter->hasNext()) {
Clock *clk = clk_iter->next();
if (clk->isGenerated())
writeGeneratedClock(clk);
else
writeClock(clk);
writeClockSlews(clk);
writeClockUncertainty(clk);
if (clk->isPropagated()) {
fprintf(stream_, "set_propagated_clock ");
writeGetClock(clk);
fprintf(stream_, "\n");
}
}
delete clk_iter;
}
void
WriteSdc::writeClock(Clock *clk) const
{
fprintf(stream_, "create_clock -name %s",
clk->name());
if (clk->addToPins())
fprintf(stream_, " -add");
fprintf(stream_, " -period ");
writeTime(clk->period());
fprintf(stream_, " -waveform ");
writeFloatSeq(clk->waveform(), scaleTime(1.0));
writeCmdComment(clk);
fprintf(stream_, " ");
writeClockPins(clk);
fprintf(stream_, "\n");
}
void
WriteSdc::writeGeneratedClock(Clock *clk) const
{
fprintf(stream_, "create_generated_clock -name %s",
clk->name());
if (clk->addToPins())
fprintf(stream_, " -add");
fprintf(stream_, " -source ");
writeGetPin(clk->srcPin());
Clock *master = clk->masterClk();
if (master && !clk->masterClkInfered()) {
fprintf(stream_, " -master_clock ");
writeGetClock(master);
}
Pin *pll_out = clk->pllOut();
if (pll_out) {
fprintf(stream_, " -pll_out ");
writeGetPin(pll_out);
}
Pin *pll_fdbk = clk->pllFdbk();
if (pll_fdbk) {
fprintf(stream_, " -pll_feedback ");
writeGetPin(pll_fdbk);
}
if (clk->combinational())
fprintf(stream_, " -combinational");
int divide_by = clk->divideBy();
if (divide_by != 0)
fprintf(stream_, " -divide_by %d", divide_by);
int multiply_by = clk->multiplyBy();
if (multiply_by != 0)
fprintf(stream_, " -multiply_by %d", multiply_by);
float duty_cycle = clk->dutyCycle();
if (duty_cycle != 0.0) {
fprintf(stream_, " -duty_cycle ");
writeFloat(duty_cycle);
}
if (clk->invert())
fprintf(stream_, " -invert");
IntSeq *edges = clk->edges();
if (edges && !edges->empty()) {
fprintf(stream_, " -edges ");
writeIntSeq(edges);
FloatSeq *edge_shifts = clk->edgeShifts();
if (edge_shifts && !edge_shifts->empty()) {
fprintf(stream_, " -edge_shift ");
writeFloatSeq(edge_shifts, scaleTime(1.0));
}
}
writeCmdComment(clk);
fprintf(stream_, " ");
writeClockPins(clk);
fprintf(stream_, "\n");
}
void
WriteSdc::writeClockPins(Clock *clk) const
{
// Sort pins.
PinSeq pins;
ClockPinIterator pin_iter(clk);
while (pin_iter.hasNext())
pins.push_back(pin_iter.next());
if (!pins.empty()) {
sort(pins, PinPathNameLess(sdc_network_));
if (pins.size() > 1)
fprintf(stream_, "\\\n ");
writeGetPins(&pins);
}
}
void
WriteSdc::writeClockSlews(Clock *clk) const
{
WriteGetClock write_clk(clk, this);
RiseFallMinMax *slews = clk->slews();
if (slews->hasValue())
writeRiseFallMinMaxTimeCmd("set_clock_transition", slews, write_clk);
}
void
WriteSdc::writeClockUncertainty(Clock *clk) const
{
float setup;
bool setup_exists;
clk->uncertainty(SetupHold::max(), setup, setup_exists);
float hold;
bool hold_exists;
clk->uncertainty(SetupHold::min(), hold, hold_exists);
if (setup_exists && hold_exists && setup == hold)
writeClockUncertainty(clk, "", setup);
else {
if (setup_exists)
writeClockUncertainty(clk, "-setup ", setup);
if (hold_exists)
writeClockUncertainty(clk, "-hold ", hold);
}
}
void
WriteSdc::writeClockUncertainty(Clock *clk,
const char *setup_hold,
float value) const
{
fprintf(stream_, "set_clock_uncertainty %s", setup_hold);
writeTime(value);
fprintf(stream_, " %s\n", clk->name());
}
void
WriteSdc::writeClockUncertaintyPins() const
{
PinClockUncertaintyMap::Iterator iter(sdc_->pin_clk_uncertainty_map_);
while (iter.hasNext()) {
const Pin *pin;
ClockUncertainties *uncertainties;
iter.next(pin, uncertainties);
writeClockUncertaintyPin(pin, uncertainties);
}
}
void
WriteSdc::writeClockUncertaintyPin(const Pin *pin,
ClockUncertainties *uncertainties)
const
{
float setup;
bool setup_exists;
uncertainties->value(SetupHold::max(), setup, setup_exists);
float hold;
bool hold_exists;
uncertainties->value(SetupHold::min(), hold, hold_exists);
if (setup_exists && hold_exists && setup == hold)
writeClockUncertaintyPin(pin, "", setup);
else {
if (setup_exists)
writeClockUncertaintyPin(pin, "-setup ", setup);
if (hold_exists)
writeClockUncertaintyPin(pin, "-hold ", hold);
}
}
void
WriteSdc::writeClockUncertaintyPin(const Pin *pin,
const char *setup_hold,
float value) const
{
fprintf(stream_, "set_clock_uncertainty %s", setup_hold);
writeTime(value);
fprintf(stream_, " ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
void
WriteSdc::writeClockLatencies() const
{
ClockLatencies::Iterator latency_iter(sdc_->clockLatencies());
while (latency_iter.hasNext()) {
ClockLatency *latency = latency_iter.next();
const Pin *pin = latency->pin();
const Clock *clk = latency->clock();
if (pin && clk) {
WriteGetPinAndClkKey write_pin(pin, clk, this);
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
write_pin);
}
else if (pin) {
WriteGetPin write_pin(pin, this);
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
write_pin);
}
else if (clk) {
WriteGetClock write_clk(clk, this);
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
write_clk);
}
}
}
void
WriteSdc::writeClockInsertions() const
{
ClockInsertions::Iterator insert_iter(sdc_->clockInsertions());
while (insert_iter.hasNext()) {
ClockInsertion *insert = insert_iter.next();
const Pin *pin = insert->pin();
const Clock *clk = insert->clock();
if (pin && clk) {
WriteGetPinAndClkKey write_pin_clk(pin, clk, this);
writeClockInsertion(insert, write_pin_clk);
}
else if (pin) {
WriteGetPin write_pin(pin, this);
writeClockInsertion(insert, write_pin);
}
else if (clk) {
WriteGetClock write_clk(clk, this);
writeClockInsertion(insert, write_clk);
}
}
}
void
WriteSdc::writeClockInsertion(ClockInsertion *insert,
WriteSdcObject &write_obj) const
{
2018-11-26 18:15:52 +01:00
RiseFallMinMax *early_values = insert->delays(EarlyLate::early());
RiseFallMinMax *late_values = insert->delays(EarlyLate::late());
2018-09-28 17:54:21 +02:00
if (early_values->equal(late_values))
writeRiseFallMinMaxTimeCmd("set_clock_latency -source",
late_values, write_obj);
else {
writeRiseFallMinMaxTimeCmd("set_clock_latency -source -early",
early_values, write_obj);
writeRiseFallMinMaxTimeCmd("set_clock_latency -source -late",
late_values, write_obj);
}
}
void
WriteSdc::writePropagatedClkPins() const
{
PinSet::Iterator pin_iter(sdc_->propagated_clk_pins_);
while (pin_iter.hasNext()) {
const Pin *pin = pin_iter.next();
fprintf(stream_, "set_propagated_clock ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
}
void
WriteSdc::writeInterClockUncertainties() const
{
InterClockUncertaintySet::Iterator
uncertainty_iter(sdc_->inter_clk_uncertainties_);
while (uncertainty_iter.hasNext()) {
InterClockUncertainty *uncertainty = uncertainty_iter.next();
writeInterClockUncertainty(uncertainty);
}
}
void
WriteSdc::
writeInterClockUncertainty(InterClockUncertainty *uncertainty) const
{
const Clock *src_clk = uncertainty->src();
const Clock *tgt_clk = uncertainty->target();
const RiseFallMinMax *src_rise =
uncertainty->uncertainties(TransRiseFall::rise());
const RiseFallMinMax *src_fall =
uncertainty->uncertainties(TransRiseFall::fall());
float value;
if (src_rise->equal(src_fall)
&& src_rise->isOneValue(value)) {
fprintf(stream_, "set_clock_uncertainty -from ");
writeGetClock(src_clk);
fprintf(stream_, " -to ");
writeGetClock(tgt_clk);
fprintf(stream_, " ");
writeTime(value);
fprintf(stream_, "\n");
}
else {
TransRiseFallIterator src_tr_iter;
while (src_tr_iter.hasNext()) {
const TransRiseFall *src_tr = src_tr_iter.next();
TransRiseFallIterator tgt_tr_iter;
while (tgt_tr_iter.hasNext()) {
const TransRiseFall *tgt_tr = tgt_tr_iter.next();
MinMaxIterator sh_iter;
while (sh_iter.hasNext()) {
const SetupHold *setup_hold = sh_iter.next();
float value;
bool exists;
sdc_->clockUncertainty(src_clk, src_tr, tgt_clk, tgt_tr,
setup_hold, value, exists);
if (exists) {
fprintf(stream_, "set_clock_uncertainty -%s_from ",
src_tr == TransRiseFall::rise() ? "rise" : "fall");
writeGetClock(uncertainty->src());
fprintf(stream_, " -%s_to ",
tgt_tr == TransRiseFall::rise() ? "rise" : "fall");
writeGetClock(uncertainty->target());
fprintf(stream_, " %s ",
setupHoldFlag(setup_hold));
writeTime(value);
fprintf(stream_, "\n");
}
}
}
}
}
}
void
WriteSdc::writeInputDelays() const
{
// Sort arrivals by pin and clock name.
PortDelaySeq delays;
InputDelayIterator *input_iter=sdc_->inputDelayIterator();
while (input_iter->hasNext()) {
InputDelay *input_delay = input_iter->next();
delays.push_back(input_delay);
}
delete input_iter;
PortDelayLess port_delay_less(sdc_network_);
sort(delays, port_delay_less);
PortDelaySeq::Iterator delay_iter(delays);
while (delay_iter.hasNext()) {
PortDelay *input_delay = delay_iter.next();
writePortDelay(input_delay, "set_input_delay");
}
}
void
WriteSdc::writeOutputDelays() const
{
// Sort departures by pin and clock name.
PortDelaySeq delays;
OutputDelayIterator *output_iter=sdc_->outputDelayIterator();
while (output_iter->hasNext()) {
OutputDelay *output_delay = output_iter->next();
delays.push_back(output_delay);
}
delete output_iter;
PortDelayLess port_delay_less(sdc_network_);
sort(delays, port_delay_less);
PortDelaySeq::Iterator delay_iter(delays);
while (delay_iter.hasNext()) {
PortDelay *output_delay = delay_iter.next();
writePortDelay(output_delay, "set_output_delay");
}
}
void
WriteSdc::writePortDelay(PortDelay *port_delay,
const char *sdc_cmd) const
{
RiseFallMinMax *delays = port_delay->delays();
float rise_min, rise_max, fall_min, fall_max;
bool rise_min_exists, rise_max_exists, fall_min_exists, fall_max_exists;
delays->value(TransRiseFall::rise(), MinMax::min(),
rise_min, rise_min_exists);
delays->value(TransRiseFall::rise(), MinMax::max(),
rise_max, rise_max_exists);
delays->value(TransRiseFall::fall(), MinMax::min(),
fall_min, fall_min_exists);
delays->value(TransRiseFall::fall(), MinMax::max(),
fall_max, fall_max_exists);
// Try to compress the four port delays.
if (rise_min_exists
&& rise_max_exists
&& fall_min_exists
&& fall_max_exists
&& rise_max == rise_min
&& fall_min == rise_min
&& fall_max == rise_min)
writePortDelay(port_delay, rise_min,
TransRiseFallBoth::riseFall(), MinMaxAll::all(), sdc_cmd);
else if (rise_min_exists
&& rise_max_exists
&& rise_max == rise_min
&& fall_min_exists
&& fall_max_exists
&& fall_min == fall_max) {
writePortDelay(port_delay, rise_min,
TransRiseFallBoth::rise(), MinMaxAll::all(), sdc_cmd);
writePortDelay(port_delay, fall_min,
TransRiseFallBoth::fall(), MinMaxAll::all(), sdc_cmd);
}
else if (rise_min_exists
&& fall_min_exists
&& rise_min == fall_min
&& rise_max_exists
&& fall_max_exists
&& rise_max == fall_max) {
writePortDelay(port_delay, rise_min,
TransRiseFallBoth::riseFall(), MinMaxAll::min(), sdc_cmd);
writePortDelay(port_delay, rise_max,
TransRiseFallBoth::riseFall(), MinMaxAll::max(), sdc_cmd);
}
else {
if (rise_min_exists)
writePortDelay(port_delay, rise_min,
TransRiseFallBoth::rise(), MinMaxAll::min(), sdc_cmd);
if (rise_max_exists)
writePortDelay(port_delay, rise_max,
TransRiseFallBoth::rise(), MinMaxAll::max(), sdc_cmd);
if (fall_min_exists)
writePortDelay(port_delay, fall_min,
TransRiseFallBoth::fall(), MinMaxAll::min(), sdc_cmd);
if (fall_max_exists)
writePortDelay(port_delay, fall_max,
TransRiseFallBoth::fall(), MinMaxAll::max(), sdc_cmd);
}
}
void
WriteSdc::writePortDelay(PortDelay *port_delay,
float delay,
const TransRiseFallBoth *tr,
const MinMaxAll *min_max,
const char *sdc_cmd) const
{
fprintf(stream_, "%s ", sdc_cmd);
writeTime(delay);
ClockEdge *clk_edge = port_delay->clkEdge();
if (clk_edge) {
writeClockKey(clk_edge->clock());
if (clk_edge->transition() == TransRiseFall::fall())
fprintf(stream_, " -clock_fall");
}
fprintf(stream_, "%s%s -add_delay ",
transRiseFallFlag(tr),
minMaxFlag(min_max));
Pin *ref_pin = port_delay->refPin();
if (ref_pin) {
fprintf(stream_, "-reference_pin ");
writeGetPin(ref_pin);
fprintf(stream_, " ");
}
Pin *pin = port_delay->pin();
if (sdc_network_->instance(pin) == instance_) {
Port *port = sdc_network_->port(pin);
writeGetPort(port);
}
else
writeGetPin(pin);
fprintf(stream_, "\n");
}
class PinClockPairNameLess
{
public:
PinClockPairNameLess(const Network *network);
bool operator()(const PinClockPair *pin_clk1,
const PinClockPair *pin_clk2) const;
private:
PinPathNameLess pin_less_;
};
PinClockPairNameLess::PinClockPairNameLess(const Network *network) :
pin_less_(network)
{
}
bool
PinClockPairNameLess::operator()(const PinClockPair *pin_clk1,
const PinClockPair *pin_clk2) const
{
const Pin *pin1 = pin_clk1->first;
const Pin *pin2 = pin_clk2->first;
const Clock *clk1 = pin_clk1->second;
const Clock *clk2 = pin_clk2->second;
return pin_less_(pin1, pin2)
|| (pin1 == pin2
&& ((clk1 == NULL && clk2)
|| (clk1 && clk2
&& clk1->index() < clk2->index())));
}
void
WriteSdc::writeClockSenses() const
{
Vector<PinClockPair*> pin_clks;
ClockSenseMap::Iterator sense_iter(sdc_->clk_sense_map_);
while (sense_iter.hasNext()) {
PinClockPair *pin_clk;
ClockSense sense;
sense_iter.next(pin_clk, sense);
pin_clks.push_back(pin_clk);
}
// Sort by pin/clk pair so regressions results are stable.
sort(pin_clks, PinClockPairNameLess(sdc_network_));
Vector<PinClockPair*>::Iterator pin_clk_iter(pin_clks);
while (pin_clk_iter.hasNext()) {
PinClockPair *pin_clk = pin_clk_iter.next();
ClockSense sense;
bool exists;
sdc_->clk_sense_map_.findKey(pin_clk, sense, exists);
if (exists)
writeClockSense(pin_clk, sense);
}
}
void
WriteSdc::writeClockSense(PinClockPair *pin_clk,
ClockSense sense) const
{
const char *flag = NULL;
if (sense == clk_sense_positive)
flag = "-positive";
else if (sense == clk_sense_negative)
flag = "-negative";
else if (sense == clk_sense_stop)
flag = "-stop_propagation";
fprintf(stream_, "set_clock_sense %s ", flag);
const Clock *clk = pin_clk->second;
if (clk) {
fprintf(stream_, "-clock ");
writeGetClock(clk);
fprintf(stream_, " ");
}
writeGetPin(pin_clk->first);
fprintf(stream_, "\n");
}
class ClockGroupLess
{
public:
bool operator()(const ClockGroup *clk_group1,
const ClockGroup *clk_group2) const;
};
bool
ClockGroupLess::operator()(const ClockGroup *clk_group1,
const ClockGroup *clk_group2) const
{
ClockSet *clk_set1 = clk_group1->clks();
ClockSet *clk_set2 = clk_group2->clks();
size_t size1 = clk_set1->size();
size_t size2 = clk_set2->size();
if (size1 < size2)
return true;
else if (size1 > size2)
return false;
else {
ClockSeq clks1, clks2;
ClockSet::Iterator clk_iter1(clk_set1);
while (clk_iter1.hasNext())
clks1.push_back(clk_iter1.next());
sort(clks1, ClockNameLess());
ClockSet::Iterator clk_iter2(clk_set2);
while (clk_iter2.hasNext())
clks2.push_back(clk_iter2.next());
sort(clks2, ClockNameLess());
ClockSeq::Iterator clk_iter3(clks1);
ClockSeq::Iterator clk_iter4(clks2);
while (clk_iter3.hasNext()
&& clk_iter4.hasNext()) {
Clock *clk1 = clk_iter3.next();
Clock *clk2 = clk_iter4.next();
int cmp = strcmp(clk1->name(), clk2->name());
if (cmp < 0)
return true;
else if (cmp > 0)
return false;
}
return false;
}
}
void
WriteSdc::writeClockGroups() const
{
ClockGroupsNameMap::Iterator groups_iter(sdc_->clk_groups_name_map_);
while (groups_iter.hasNext()) {
ClockGroups *clk_groups = groups_iter.next();
writeClockGroups(clk_groups);
}
}
void
WriteSdc::writeClockGroups(ClockGroups *clk_groups) const
{
fprintf(stream_, "set_clock_groups -name %s ", clk_groups->name());
if (clk_groups->logicallyExclusive())
fprintf(stream_, "-logically_exclusive \\\n");
else if (clk_groups->physicallyExclusive())
fprintf(stream_, "-physically_exclusive \\\n");
else if (clk_groups->asynchronous())
fprintf(stream_, "-asynchronous \\\n");
if (clk_groups->allowPaths())
fprintf(stream_, "-allow_paths \\\n");
Vector<ClockGroup*> groups;
ClockGroupSet::Iterator group_iter1(clk_groups->groups());
while (group_iter1.hasNext()) {
ClockGroup *clk_group = group_iter1.next();
groups.push_back(clk_group);
}
sort(groups, ClockGroupLess());
bool first = true;
Vector<ClockGroup*>::Iterator group_iter2(groups);
while (group_iter2.hasNext()) {
ClockGroup *clk_group = group_iter2.next();
if (!first)
fprintf(stream_, "\\\n");
fprintf(stream_, " -group ");
writeGetClocks(clk_group->clks());
first = false;
}
writeCmdComment(clk_groups);
fprintf(stream_, "\n");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDisables() const
{
writeDisabledCells();
writeDisabledPorts();
writeDisabledLibPorts();
writeDisabledInstances();
writeDisabledPins();
writeDisabledEdges();
}
void
WriteSdc::writeDisabledCells() const
{
DisabledCellPortsSeq disables;
sortDisabledCellPortsMap(sdc_->disabledCellPorts(), disables);
DisabledCellPortsSeq::Iterator disabled_iter(disables);
while (disabled_iter.hasNext()) {
DisabledCellPorts *disable = disabled_iter.next();
LibertyCell *cell = disable->cell();
if (disable->all()) {
fprintf(stream_, "set_disable_timing ");
writeGetLibCell(cell);
fprintf(stream_, "\n");
}
if (disable->fromTo()) {
LibertyPortPairSeq pairs;
sortLibertyPortPairSet(disable->fromTo(), pairs);
LibertyPortPairSeq::Iterator pair_iter(pairs);
while (pair_iter.hasNext()) {
LibertyPortPair *from_to = pair_iter.next();
2018-12-05 23:18:41 +01:00
const LibertyPort *from = from_to->first;
const LibertyPort *to = from_to->second;
2018-09-28 17:54:21 +02:00
fprintf(stream_, "set_disable_timing -from {%s} -to {%s} ",
from->name(),
to->name());
writeGetLibCell(cell);
fprintf(stream_, "\n");
}
}
if (disable->from()) {
LibertyPortSeq from;
sortLibertyPortSet(disable->from(), from);
LibertyPortSeq::Iterator from_iter(from);
while (from_iter.hasNext()) {
LibertyPort *from_port = from_iter.next();
fprintf(stream_, "set_disable_timing -from {%s} ",
from_port->name());
writeGetLibCell(cell);
fprintf(stream_, "\n");
}
}
if (disable->to()) {
LibertyPortSeq to;
sortLibertyPortSet(disable->to(), to);
LibertyPortSeq::Iterator to_iter(to);
while (to_iter.hasNext()) {
LibertyPort *to_port = to_iter.next();
fprintf(stream_, "set_disable_timing -to {%s} ",
to_port->name());
writeGetLibCell(cell);
fprintf(stream_, "\n");
}
}
if (disable->timingArcSets()) {
// The only syntax to disable timing arc sets disables all of the
// cell's timing arc sets.
fprintf(stream_, "set_disable_timing ");
writeGetTimingArcsOfOjbects(cell);
fprintf(stream_, "\n");
}
}
}
void
WriteSdc::writeDisabledPorts() const
{
PortSeq ports;
sortPortSet(sdc_->disabledPorts(), sdc_network_, ports);
PortSeq::Iterator port_iter(ports);
while (port_iter.hasNext()) {
Port *port = port_iter.next();
fprintf(stream_, "set_disable_timing ");
writeGetPort(port);
fprintf(stream_, "\n");
}
}
void
WriteSdc::writeDisabledLibPorts() const
{
LibertyPortSeq ports;
sortLibertyPortSet(sdc_->disabledLibPorts(), ports);
LibertyPortSeq::Iterator port_iter(ports);
while (port_iter.hasNext()) {
LibertyPort *port = port_iter.next();
fprintf(stream_, "set_disable_timing ");
writeGetLibPin(port);
fprintf(stream_, "\n");
}
}
void
WriteSdc::writeDisabledInstances() const
{
DisabledInstancePortsSeq disables;
sortDisabledInstancePortsMap(sdc_->disabledInstancePorts(),
sdc_network_, disables);
DisabledInstancePortsSeq::Iterator disabled_iter(disables);
while (disabled_iter.hasNext()) {
DisabledInstancePorts *disable = disabled_iter.next();
Instance *inst = disable->instance();
if (disable->all()) {
fprintf(stream_, "set_disable_timing ");
writeGetInstance(inst);
fprintf(stream_, "\n");
}
else if (disable->fromTo()) {
LibertyPortPairSeq pairs;
sortLibertyPortPairSet(disable->fromTo(), pairs);
LibertyPortPairSeq::Iterator pair_iter(pairs);
while (pair_iter.hasNext()) {
LibertyPortPair *from_to = pair_iter.next();
2018-12-05 23:18:41 +01:00
const LibertyPort *from_port = from_to->first;
const LibertyPort *to_port = from_to->second;
2018-09-28 17:54:21 +02:00
fprintf(stream_, "set_disable_timing -from {%s} -to {%s} ",
from_port->name(),
to_port->name());
writeGetInstance(inst);
fprintf(stream_, "\n");
}
}
if (disable->from()) {
LibertyPortSeq from;
sortLibertyPortSet(disable->from(), from);
LibertyPortSeq::Iterator from_iter(from);
while (from_iter.hasNext()) {
LibertyPort *from_port = from_iter.next();
fprintf(stream_, "set_disable_timing -from {%s} ",
from_port->name());
writeGetInstance(inst);
fprintf(stream_, "\n");
}
}
if (disable->to()) {
LibertyPortSeq to;
sortLibertyPortSet(disable->to(), to);
LibertyPortSeq::Iterator to_iter(to);
while (to_iter.hasNext()) {
LibertyPort *to_port = to_iter.next();
fprintf(stream_, "set_disable_timing -to {%s} ",
to_port->name());
writeGetInstance(inst);
fprintf(stream_, "\n");
}
}
}
}
void
WriteSdc::writeDisabledPins() const
{
PinSeq pins;
sortPinSet(sdc_->disabledPins(), sdc_network_, pins);
PinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
fprintf(stream_, "set_disable_timing ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
}
void
WriteSdc::writeDisabledEdges() const
{
EdgeSeq edges;
EdgeSet::Iterator edge_iter(sdc_->disabledEdges());
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
edges.push_back(edge);
}
sortEdges(&edges, sdc_network_, graph_);
EdgeSeq::Iterator edge_iter2(edges);
while (edge_iter2.hasNext()) {
Edge *edge = edge_iter2.next();
EdgeSet matches;
findMatchingEdges(edge, matches);
if (matches.size() == 1)
writeDisabledEdge(edge);
else if (edgeSenseIsUnique(edge, matches))
writeDisabledEdgeSense(edge);
}
}
void
WriteSdc::findMatchingEdges(Edge *edge,
EdgeSet &matches) const
{
Vertex *from_vertex = edge->from(graph_);
Vertex *to_vertex = edge->to(graph_);
Pin *to_pin = to_vertex->pin();
VertexOutEdgeIterator edge_iter(from_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *out_edge = edge_iter.next();
if (out_edge->to(graph_)->pin() == to_pin)
matches.insert(out_edge);
}
}
bool
WriteSdc::edgeSenseIsUnique(Edge *edge,
EdgeSet &matches) const
{
EdgeSet::Iterator match_iter(matches);
while (match_iter.hasNext()) {
Edge *match = match_iter.next();
if (match != edge
&& match->sense() == edge->sense())
return false;
}
return true;
}
void
WriteSdc::writeDisabledEdge(Edge *edge) const
{
fprintf(stream_, "set_disable_timing ");
writeGetTimingArcs(edge);
fprintf(stream_, "\n");
}
void
WriteSdc::writeDisabledEdgeSense(Edge *edge) const
{
fprintf(stream_, "set_disable_timing ");
const char *sense = timingSenseString(edge->sense());
const char *filter = stringPrintTmp(strlen(sense) + strlen("sense == ") + 1,
"sense == %s", sense);
writeGetTimingArcs(edge, filter);
fprintf(stream_, "\n");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeExceptions() const
{
ExceptionPathSeq exceptions;
sortExceptions(sdc_->exceptions(), exceptions, sdc_network_);
ExceptionPathSeq::Iterator except_iter(exceptions);
while (except_iter.hasNext()) {
ExceptionPath *exception = except_iter.next();
if (!exception->isFilter()
&& !exception->isLoop())
writeException(exception);
}
}
void
WriteSdc::writeException(ExceptionPath *exception) const
{
writeExceptionCmd(exception);
if (exception->from())
writeExceptionFrom(exception->from());
if (exception->thrus()) {
ExceptionThruSeq::Iterator thru_iter(exception->thrus());
while (thru_iter.hasNext()) {
ExceptionThru *thru = thru_iter.next();
writeExceptionThru(thru);
}
}
if (exception->to())
writeExceptionTo(exception->to());
writeExceptionValue(exception);
writeCmdComment(exception);
fprintf(stream_, "\n");
}
void
WriteSdc::writeExceptionCmd(ExceptionPath *exception) const
{
if (exception->isFalse()) {
fprintf(stream_, "set_false_path");
writeSetupHoldFlag(exception->minMax());
}
else if (exception->isMultiCycle()) {
fprintf(stream_, "set_multicycle_path");
const MinMaxAll *min_max = exception->minMax();
writeSetupHoldFlag(min_max);
if (min_max == MinMaxAll::min()) {
// For hold MCPs default is -start.
if (exception->useEndClk())
fprintf(stream_, " -end");
}
else {
// For setup MCPs default is -end.
if (!exception->useEndClk())
fprintf(stream_, " -start");
}
}
else if (exception->isPathDelay()) {
if (exception->minMax() == MinMaxAll::max())
fprintf(stream_, "set_max_delay");
else
fprintf(stream_, "set_min_delay");
if (exception->ignoreClkLatency())
fprintf(stream_, " -ignore_clock_latency");
}
else if (exception->isGroupPath()) {
if (exception->isDefault())
fprintf(stream_, "group_path -default");
else
fprintf(stream_, "group_path -name %s", exception->name());
}
else
internalError("unknown exception type");
}
void
WriteSdc::writeExceptionValue(ExceptionPath *exception) const
{
if (exception->isMultiCycle())
fprintf(stream_, " %d",
exception->pathMultiplier());
else if (exception->isPathDelay()) {
fprintf(stream_, " ");
writeTime(exception->delay());
}
}
void
WriteSdc::writeExceptionFrom(ExceptionFrom *from) const
{
writeExceptionFromTo(from, "from");
}
void
WriteSdc::writeExceptionTo(ExceptionTo *to) const
{
const TransRiseFallBoth *end_tr = to->endTransition();
if (end_tr != TransRiseFallBoth::riseFall())
fprintf(stream_, "%s ", transRiseFallFlag(end_tr));
if (to->hasObjects())
writeExceptionFromTo(to, "to");
}
void
WriteSdc::writeExceptionFromTo(ExceptionFromTo *from_to,
const char *from_to_key) const
{
const TransRiseFallBoth *tr = from_to->transition();
const char *tr_prefix = "-";
if (tr == TransRiseFallBoth::rise())
tr_prefix = "-rise_";
else if (tr == TransRiseFallBoth::fall())
tr_prefix = "-fall_";
fprintf(stream_, "\\\n %s%s ", tr_prefix, from_to_key);
bool multi_objs =
((from_to->pins() ? from_to->pins()->size() : 0)
+ (from_to->clks() ? from_to->clks()->size() : 0)
+ (from_to->instances() ? from_to->instances()->size() : 0)) > 1;
if (multi_objs)
fprintf(stream_, "[list ");
bool first = true;
if (from_to->pins()) {
PinSeq pins;
sortPinSet(from_to->pins(), sdc_network_, pins);
PinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
if (multi_objs && !first)
fprintf(stream_, "\\\n ");
writeGetPin(pin);
first = false;
}
}
if (from_to->clks())
writeGetClocks(from_to->clks(), multi_objs, first);
if (from_to->instances()) {
InstanceSeq insts;
sortInstanceSet(from_to->instances(), sdc_network_, insts);
InstanceSeq::Iterator inst_iter(insts);
while (inst_iter.hasNext()) {
Instance *inst = inst_iter.next();
if (multi_objs && !first)
fprintf(stream_, "\\\n ");
writeGetInstance(inst);
first = false;
}
}
if (multi_objs)
fprintf(stream_, "]");
}
void
WriteSdc::writeExceptionThru(ExceptionThru *thru) const
{
const TransRiseFallBoth *tr = thru->transition();
const char *tr_prefix = "-";
if (tr == TransRiseFallBoth::rise())
tr_prefix = "-rise_";
else if (tr == TransRiseFallBoth::fall())
tr_prefix = "-fall_";
fprintf(stream_, "\\\n %sthrough ", tr_prefix);
bool multi_objs =
((thru->pins() ? thru->pins()->size() : 0)
+ (thru->nets() ? thru->nets()->size() : 0)
+ (thru->instances() ? thru->instances()->size() : 0)) > 1;
if (multi_objs)
fprintf(stream_, "[list ");
bool first = true;
if (thru->pins()) {
PinSeq pins;
sortPinSet(thru->pins(), sdc_network_, pins);
PinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
if (multi_objs && !first)
fprintf(stream_, "\\\n ");
writeGetPin(pin);
first = false;
}
}
if (thru->nets()) {
NetSeq nets;
sortNetSet(thru->nets(), sdc_network_, nets);
NetSeq::Iterator net_iter(nets);
while (net_iter.hasNext()) {
Net *net = net_iter.next();
if (multi_objs && !first)
fprintf(stream_, "\\\n ");
writeGetNet(net);
first = false;
}
}
if (thru->instances()) {
InstanceSeq insts;
sortInstanceSet(thru->instances(), sdc_network_, insts);
InstanceSeq::Iterator inst_iter(insts);
while (inst_iter.hasNext()) {
Instance *inst = inst_iter.next();
if (multi_objs && !first)
fprintf(stream_, "\\\n ");
writeGetInstance(inst);
first = false;
}
}
if (multi_objs)
fprintf(stream_, "]");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDataChecks() const
{
Vector<DataCheck*> checks;
DataChecksMap::Iterator checks_iter(sdc_->data_checks_to_map_);
while (checks_iter.hasNext()) {
DataCheckSet *checks1 = checks_iter.next();
DataCheckSet::Iterator check_iter(checks1);
while (check_iter.hasNext()) {
DataCheck *check = check_iter.next();
checks.push_back(check);
}
}
sort(checks, DataCheckLess(sdc_network_));
Vector<DataCheck*>::Iterator check_iter(checks);
while (check_iter.hasNext()) {
DataCheck *check = check_iter.next();
writeDataCheck(check);
}
}
void
WriteSdc::writeDataCheck(DataCheck *check) const
{
MinMaxIterator mm_iter;
while (mm_iter.hasNext()) {
SetupHold *setup_hold = mm_iter.next();
float margin;
bool one_value;
check->marginIsOneValue(setup_hold, margin, one_value);
if (one_value)
writeDataCheck(check, TransRiseFallBoth::riseFall(),
TransRiseFallBoth::riseFall(), setup_hold, margin);
else {
TransRiseFallIterator from_tr_iter;
while (from_tr_iter.hasNext()) {
TransRiseFall *from_tr = from_tr_iter.next();
TransRiseFallIterator to_tr_iter;
while (to_tr_iter.hasNext()) {
TransRiseFall *to_tr = to_tr_iter.next();
float margin;
bool margin_exists;
check->margin(from_tr, to_tr, setup_hold, margin, margin_exists);
if (margin_exists) {
writeDataCheck(check, from_tr->asRiseFallBoth(),
to_tr->asRiseFallBoth(), setup_hold, margin);
}
}
}
}
}
}
void
WriteSdc::writeDataCheck(DataCheck *check,
TransRiseFallBoth *from_tr,
TransRiseFallBoth *to_tr,
SetupHold *setup_hold,
float margin) const
{
const char *from_key = "-from";
if (from_tr == TransRiseFallBoth::rise())
from_key = "-rise_from";
else if (from_tr == TransRiseFallBoth::fall())
from_key = "-fall_from";
fprintf(stream_, "set_data_check %s ", from_key);
writeGetPin(check->from());
const char *to_key = "-to";
if (to_tr == TransRiseFallBoth::rise())
to_key = "-rise_to";
else if (to_tr == TransRiseFallBoth::fall())
to_key = "-fall_to";
fprintf(stream_, " %s ", to_key);
writeGetPin(check->to());
fprintf(stream_, "%s ",
setupHoldFlag(setup_hold));
writeTime(margin);
fprintf(stream_, "\n");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeEnvironment() const
{
writeCommentSection("Environment");
writeOperatingConditions();
writeWireload();
writePinLoads();
writeDriveResistances();
writeDrivingCells();
writeInputTransitions();
writeNetResistances();
writeConstants();
writeCaseAnalysis();
writeDeratings();
}
void
WriteSdc::writeOperatingConditions() const
{
OperatingConditions *cond = sdc_->operatingConditions(MinMax::max());
if (cond)
fprintf(stream_, "set_operating_conditions %s\n", cond->name());
}
void
WriteSdc::writeWireload() const
{
WireloadMode wireload_mode = sdc_->wireloadMode();
if (wireload_mode != wire_load_mode_unknown)
fprintf(stream_, "set_wire_load_mode \"%s\"\n",
wireloadModeString(wireload_mode));
}
void
WriteSdc::writePinLoads() const
{
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
writePortLoads(port);
}
delete port_iter;
}
void
WriteSdc::writePortLoads(Port *port) const
{
PortExtCap *ext_cap = sdc_->portExtCap(port);
if (ext_cap) {
WriteGetPort write_port(port, this);
writeRiseFallMinMaxCapCmd("set_load -pin_load",
ext_cap->pinCap(),
write_port);
writeRiseFallMinMaxCapCmd("set_load -wire_load",
ext_cap->wireCap(),
write_port);
writeMinMaxIntValuesCmd("set_port_fanout_number",
ext_cap->fanout(), write_port);
}
}
void
WriteSdc::writeDriveResistances() const
{
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
InputDrive *drive = sdc_->findInputDrive(port);
if (drive) {
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
const TransRiseFall *tr = tr_iter.next();
if (drive->driveResistanceMinMaxEqual(tr)) {
float res;
bool exists;
drive->driveResistance(tr, MinMax::max(), res, exists);
fprintf(stream_, "set_drive %s ",
transRiseFallFlag(tr));
writeResistance(res);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
else {
MinMaxIterator mm_iter;
while (mm_iter.hasNext()) {
const MinMax *mm = mm_iter.next();
float res;
bool exists;
drive->driveResistance(tr, mm, res, exists);
if (exists) {
fprintf(stream_, "set_drive %s %s ",
transRiseFallFlag(tr),
minMaxFlag(mm));
writeResistance(res);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
}
}
}
}
}
delete port_iter;
}
void
WriteSdc::writeDrivingCells() const
{
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
InputDrive *drive = sdc_->findInputDrive(port);
if (drive) {
InputDriveCell *drive_rise_min = drive->driveCell(TransRiseFall::rise(),
MinMax::min());
InputDriveCell *drive_rise_max = drive->driveCell(TransRiseFall::rise(),
MinMax::max());
InputDriveCell *drive_fall_min = drive->driveCell(TransRiseFall::fall(),
MinMax::min());
InputDriveCell *drive_fall_max = drive->driveCell(TransRiseFall::fall(),
MinMax::max());
if (drive_rise_min
&& drive_rise_max
&& drive_fall_min
&& drive_fall_max
&& drive_rise_min->equal(drive_rise_max)
&& drive_rise_min->equal(drive_fall_min)
&& drive_rise_min->equal(drive_fall_max))
// Only write one set_driving_cell if possible.
writeDrivingCell(port, drive_rise_min, NULL, NULL);
else {
if (drive_rise_min
&& drive_rise_max
&& drive_rise_min->equal(drive_rise_max))
writeDrivingCell(port, drive_rise_min, TransRiseFall::rise(), NULL);
else {
if (drive_rise_min)
writeDrivingCell(port, drive_rise_min, TransRiseFall::rise(),
MinMax::min());
if (drive_rise_max)
writeDrivingCell(port, drive_rise_max, TransRiseFall::rise(),
MinMax::max());
}
if (drive_fall_min
&& drive_fall_max
&& drive_fall_min->equal(drive_fall_max))
writeDrivingCell(port, drive_fall_min, TransRiseFall::fall(), NULL);
else {
if (drive_fall_min)
writeDrivingCell(port, drive_fall_min, TransRiseFall::fall(),
MinMax::min());
if (drive_fall_max)
writeDrivingCell(port, drive_fall_max, TransRiseFall::fall(),
MinMax::max());
}
}
}
}
delete port_iter;
}
void
WriteSdc::writeDrivingCell(Port *port,
InputDriveCell *drive_cell,
const TransRiseFall *tr,
const MinMax *min_max) const
{
LibertyCell *cell = drive_cell->cell();
LibertyPort *from_port = drive_cell->fromPort();
LibertyPort *to_port = drive_cell->toPort();
float *from_slews = drive_cell->fromSlews();
LibertyLibrary *lib = cell->libertyLibrary();
fprintf(stream_, "set_driving_cell");
if (tr)
fprintf(stream_, " %s", transRiseFallFlag(tr));
if (min_max)
fprintf(stream_, " %s", minMaxFlag(min_max));
fprintf(stream_, " -library %s -lib_cell %s",
lib->name(),
cell->name());
if (from_port)
fprintf(stream_, " -from_pin {%s}",
from_port->name());
fprintf(stream_,
" -pin {%s} -input_transition_rise ",
to_port->name());
writeTime(from_slews[TransRiseFall::riseIndex()]);
fprintf(stream_, " -input_transition_fall ");
writeTime(from_slews[TransRiseFall::fallIndex()]);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
void
WriteSdc::writeInputTransitions() const
{
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
InputDrive *drive = sdc_->findInputDrive(port);
if (drive) {
RiseFallMinMax *slews = drive->slews();
WriteGetPort write_port(port, this);
writeRiseFallMinMaxTimeCmd("set_input_transition", slews, write_port);
}
}
delete port_iter;
}
void
WriteSdc::writeNetResistances() const
{
NetResistanceMap *net_res_map = sdc_->netResistances();
NetSeq nets;
NetResistanceMap::Iterator res_iter(net_res_map);
while (res_iter.hasNext()) {
Net *net;
MinMaxFloatValues values;
res_iter.next(net, values);
nets.push_back(net);
}
sort(nets, NetPathNameLess(sdc_network_));
NetSeq::Iterator net_iter(nets);
while (net_iter.hasNext()) {
Net *net = net_iter.next();
float min_res, max_res;
bool min_exists, max_exists;
sdc_->resistance(net, MinMax::min(), min_res, min_exists);
sdc_->resistance(net, MinMax::max(), max_res, max_exists);
if (min_exists && max_exists
&& min_res == max_res)
writeNetResistance(net, MinMaxAll::all(), min_res);
else {
if (min_exists)
writeNetResistance(net, MinMaxAll::min(), min_res);
if (max_exists)
writeNetResistance(net, MinMaxAll::max(), max_res);
}
}
}
void
WriteSdc::writeNetResistance(Net *net,
const MinMaxAll *min_max,
float res) const
{
fprintf(stream_, "set_resistance ");
writeResistance(res);
fprintf(stream_, "%s ", minMaxFlag(min_max));
writeGetNet(net);
fprintf(stream_, "\n");
}
void
WriteSdc::writeConstants() const
{
PinSeq pins;
sortedLogicValuePins(sdc_->logicValues(), pins);
PinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
writeConstant(pin);
}
}
void
WriteSdc::writeConstant(Pin *pin) const
{
const char *cmd = setConstantCmd(pin);
fprintf(stream_, "%s ", cmd);
writeGetPin(pin);
fprintf(stream_, "\n");
}
const char *
WriteSdc::setConstantCmd(Pin *pin) const
{
LogicValue value;
bool exists;
sdc_->logicValue(pin, value, exists);
switch (value) {
case logic_zero:
return "set_logic_zero";
case logic_one:
return "set_logic_one";
case logic_unknown:
return "set_logic_dc";
case logic_rise:
case logic_fall:
default:
internalError("illegal set_logic value");
}
}
void
WriteSdc::writeCaseAnalysis() const
{
PinSeq pins;
sortedLogicValuePins(sdc_->caseLogicValues(), pins);
PinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
writeCaseAnalysis(pin);
}
}
void
WriteSdc::writeCaseAnalysis(Pin *pin) const
{
const char *value_str = caseAnalysisValueStr(pin);
fprintf(stream_, "set_case_analysis %s ", value_str);
writeGetPin(pin);
fprintf(stream_, "\n");
}
const char *
WriteSdc::caseAnalysisValueStr(Pin *pin) const
{
LogicValue value;
bool exists;
sdc_->caseLogicValue(pin, value, exists);
switch (value) {
case logic_zero:
return "0";
case logic_one:
return "1";
case logic_rise:
return "rising";
case logic_fall:
return "falling";
case logic_unknown:
default:
internalError("invalid set_case_analysis value");
}
}
void
WriteSdc::sortedLogicValuePins(LogicValueMap *value_map,
PinSeq &pins) const
{
LogicValueMap::ConstIterator value_iter(value_map);
while (value_iter.hasNext()) {
LogicValue value;
const Pin *pin;
value_iter.next(pin, value);
pins.push_back(const_cast<Pin*>(pin));
}
// Sort pins.
sort(pins, PinPathNameLess(sdc_network_));
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDeratings() const
{
DeratingFactorsGlobal *factors = sdc_->derating_factors_;
if (factors)
writeDerating(factors);
NetDeratingFactorsMap::Iterator net_iter(sdc_->net_derating_factors_);
while (net_iter.hasNext()) {
const Net *net;
DeratingFactorsNet *factors;
net_iter.next(net, factors);
WriteGetNet write_net(net, this);
MinMaxIterator mm_iter;
while (mm_iter.hasNext()) {
const MinMax *early_late = mm_iter.next();
writeDerating(factors, timing_derate_net_delay, early_late, &write_net);
}
}
InstDeratingFactorsMap::Iterator inst_iter(sdc_->inst_derating_factors_);
while (inst_iter.hasNext()) {
const Instance *inst;
DeratingFactorsCell *factors;
inst_iter.next(inst, factors);
WriteGetInstance write_inst(inst, this);
writeDerating(factors, &write_inst);
}
CellDeratingFactorsMap::Iterator cell_iter(sdc_->cell_derating_factors_);
while (cell_iter.hasNext()) {
const LibertyCell *cell;
DeratingFactorsCell *factors;
cell_iter.next(cell, factors);
WriteGetLibCell write_cell(cell, this);
writeDerating(factors, &write_cell);
}
}
void
WriteSdc::writeDerating(DeratingFactorsGlobal *factors) const
{
MinMaxIterator mm_iter;
while (mm_iter.hasNext()) {
const MinMax *early_late = mm_iter.next();
bool delay_is_one_value, check_is_one_value, net_is_one_value;
float delay_value, check_value, net_value;
factors->factors(timing_derate_cell_delay)->isOneValue(early_late,
delay_is_one_value,
delay_value);
factors->factors(timing_derate_net_delay)->isOneValue(early_late,
net_is_one_value,
net_value);
DeratingFactors *cell_check_factors =
factors->factors(timing_derate_cell_check);
cell_check_factors->isOneValue(early_late, check_is_one_value, check_value);
if (delay_is_one_value
&& net_is_one_value
&& delay_value == net_value
&& (!cell_check_factors->hasValue()
|| (check_is_one_value && check_value == 1.0))) {
if (delay_value != 1.0) {
fprintf(stream_, "set_timing_derate %s ", earlyLateFlag(early_late));
writeFloat(delay_value);
fprintf(stream_, "\n");
}
}
else {
for (int type_index = 0;
type_index < timing_derate_type_count;
type_index++) {
TimingDerateType type = static_cast<TimingDerateType>(type_index);
DeratingFactors *type_factors = factors->factors(type);
writeDerating(type_factors, type, early_late, NULL);
}
}
}
}
void
WriteSdc::writeDerating(DeratingFactorsCell *factors,
WriteSdcObject *write_obj) const
{
MinMaxIterator mm_iter;
while (mm_iter.hasNext()) {
const MinMax *early_late = mm_iter.next();
DeratingFactors *delay_factors=factors->factors(timing_derate_cell_delay);
writeDerating(delay_factors, timing_derate_cell_delay, early_late, write_obj);
DeratingFactors *check_factors=factors->factors(timing_derate_cell_check);
writeDerating(check_factors, timing_derate_cell_check, early_late, write_obj);
}
}
void
WriteSdc::writeDerating(DeratingFactors *factors,
TimingDerateType type,
const MinMax *early_late,
WriteSdcObject *write_obj) const
{
const char *type_key = timingDerateTypeKeyword(type);
bool is_one_value;
float value;
factors->isOneValue(early_late, is_one_value, value);
if (is_one_value) {
if (value != 1.0) {
fprintf(stream_, "set_timing_derate %s %s ",
type_key,
earlyLateFlag(early_late));
writeFloat(value);
if (write_obj) {
fprintf(stream_, " ");
write_obj->write();
}
fprintf(stream_, "\n");
}
}
else {
for (int clk_data_index = 0;
clk_data_index < path_clk_or_data_count;
clk_data_index++) {
PathClkOrData clk_data = static_cast<PathClkOrData>(clk_data_index);
static const char *clk_data_keys[] = {"-clock", "-data"};
const char *clk_data_key = clk_data_keys[clk_data_index];
factors->isOneValue(clk_data, early_late, is_one_value, value);
if (is_one_value) {
if (value != 1.0) {
fprintf(stream_, "set_timing_derate %s %s %s ",
type_key,
earlyLateFlag(early_late),
clk_data_key);
writeFloat(value);
if (write_obj) {
fprintf(stream_, " ");
write_obj->write();
}
fprintf(stream_, "\n");
}
}
else {
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
MinMaxIterator mm_iter;
float factor;
bool exists;
factors->factor(clk_data, tr, early_late, factor, exists);
if (exists) {
fprintf(stream_, "set_timing_derate %s %s %s %s ",
type_key,
clk_data_key,
transRiseFallFlag(tr),
earlyLateFlag(early_late));
writeFloat(factor);
if (write_obj) {
fprintf(stream_, " ");
write_obj->write();
}
fprintf(stream_, "\n");
}
}
}
}
}
}
static const char *
timingDerateTypeKeyword(TimingDerateType type)
{
static const char *type_keys[] = {"-cell_delay","-cell_check","-net_delay"};
return type_keys[static_cast<int>(type)];
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDesignRules() const
{
writeCommentSection("Design Rules");
writeMinPulseWidths();
writeLatchBorowLimits();
writeSlewLimits();
writeCapLimits();
writeFanoutLimits();
writeMaxArea();
}
void
WriteSdc::writeMinPulseWidths() const
{
PinMinPulseWidthMap::Iterator
pin_iter(sdc_->pin_min_pulse_width_map_);
while (pin_iter.hasNext()) {
const Pin *pin;
RiseFallValues *min_widths;
pin_iter.next(pin, min_widths);
WriteGetPin write_obj(pin, this);
writeMinPulseWidths(min_widths, write_obj);
}
InstMinPulseWidthMap::Iterator
inst_iter(sdc_->inst_min_pulse_width_map_);
while (inst_iter.hasNext()) {
const Instance *inst;
RiseFallValues *min_widths;
inst_iter.next(inst, min_widths);
WriteGetInstance write_obj(inst, this);
writeMinPulseWidths(min_widths, write_obj);
}
ClockMinPulseWidthMap::Iterator
clk_iter(sdc_->clk_min_pulse_width_map_);
while (clk_iter.hasNext()) {
const Clock *clk;
RiseFallValues *min_widths;
clk_iter.next(clk, min_widths);
WriteGetClock write_obj(clk, this);
writeMinPulseWidths(min_widths, write_obj);
}
}
void
WriteSdc::writeMinPulseWidths(RiseFallValues *min_widths,
WriteSdcObject &write_obj) const
{
bool hi_exists, low_exists;
float hi, low;
min_widths->value(TransRiseFall::rise(), hi, hi_exists);
min_widths->value(TransRiseFall::fall(), low, low_exists);
if (hi_exists && low_exists
&& hi == low)
writeMinPulseWidth("", hi, write_obj);
else {
if (hi_exists)
writeMinPulseWidth("-high ", hi, write_obj);
if (low_exists)
writeMinPulseWidth("-low ", low, write_obj);
}
}
void
WriteSdc::writeMinPulseWidth(const char *hi_low,
float value,
WriteSdcObject &write_obj) const
{
fprintf(stream_, "set_min_pulse_width %s", hi_low);
writeTime(value);
fprintf(stream_, " ");
write_obj.write();
fprintf(stream_, "\n");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeLatchBorowLimits() const
{
PinLatchBorrowLimitMap::Iterator
pin_iter(sdc_->pin_latch_borrow_limit_map_);
while (pin_iter.hasNext()) {
const Pin *pin;
float limit;
pin_iter.next(pin, limit);
fprintf(stream_, "set_max_time_borrow ");
writeTime(limit);
fprintf(stream_, " ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
InstLatchBorrowLimitMap::Iterator
inst_iter(sdc_->inst_latch_borrow_limit_map_);
while (inst_iter.hasNext()) {
const Instance *inst;
float limit;
inst_iter.next(inst, limit);
fprintf(stream_, "set_max_time_borrow ");
writeTime(limit);
fprintf(stream_, " ");
writeGetInstance(inst);
fprintf(stream_, "\n");
}
ClockLatchBorrowLimitMap::Iterator
clk_iter(sdc_->clk_latch_borrow_limit_map_);
while (clk_iter.hasNext()) {
const Clock *clk;
float limit;
clk_iter.next(clk, limit);
fprintf(stream_, "set_max_time_borrow ");
writeTime(limit);
fprintf(stream_, " ");
writeGetClock(clk);
fprintf(stream_, "\n");
}
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeSlewLimits() const
{
const MinMax *min_max = MinMax::max();
float slew;
bool exists;
sdc_->slewLimit(cell_, min_max, slew, exists);
if (exists) {
fprintf(stream_, "set_max_transition ");
writeTime(slew);
fprintf(stream_, " [current_design]\n");
}
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
sdc_->slewLimit(port, min_max, slew, exists);
if (exists) {
fprintf(stream_, "set_max_transition ");
writeTime(slew);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
}
delete port_iter;
ConstPinSeq pins;
sdc_->slewLimitPins(pins);
sort(pins, PinPathNameLess(network_));
ConstPinSeq::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
const Pin *pin = pin_iter.next();
float slew;
bool exists;
sdc_->slewLimit(pin, min_max, slew, exists);
if (exists) {
fprintf(stream_, "set_max_transition ");
writeTime(slew);
fprintf(stream_, " ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
}
writeClkSlewLimits();
}
void
WriteSdc::writeClkSlewLimits() const
{
const MinMax *min_max = MinMax::max();
ClockSeq clks;
sdc_->sortedClocks(clks);
ClockSeq::Iterator clk_iter(clks);
while (clk_iter.hasNext()) {
Clock *clk = clk_iter.next();
float rise_clk_limit, fall_clk_limit, rise_data_limit, fall_data_limit;
bool rise_clk_exists, fall_clk_exists, rise_data_exists, fall_data_exists;
clk->slewLimit(TransRiseFall::rise(), path_clk, min_max,
rise_clk_limit, rise_clk_exists);
clk->slewLimit(TransRiseFall::fall(), path_clk, min_max,
fall_clk_limit, fall_clk_exists);
clk->slewLimit(TransRiseFall::rise(), path_data, min_max,
rise_data_limit, rise_data_exists);
clk->slewLimit(TransRiseFall::fall(), path_data, min_max,
fall_data_limit, fall_data_exists);
if (rise_clk_exists && fall_clk_exists
&& rise_data_exists && fall_data_exists
&& fall_clk_limit == rise_clk_limit
&& rise_data_limit == rise_clk_limit
&& fall_data_limit == rise_clk_limit)
writeClkSlewLimit("", "", clk, rise_clk_limit);
else {
if (rise_clk_exists && fall_clk_exists
&& fall_clk_limit == rise_clk_limit)
writeClkSlewLimit("-clock_path ", "", clk, rise_clk_limit);
else {
if (rise_clk_exists)
writeClkSlewLimit("-clock_path ", "-rise ", clk, rise_clk_limit);
if (fall_clk_exists)
writeClkSlewLimit("-clock_path ", "-fall ", clk, fall_clk_limit);
}
if (rise_data_exists && fall_data_exists
&& fall_data_limit == rise_data_limit)
writeClkSlewLimit("-data_path ", "", clk, rise_data_limit);
else {
if (rise_data_exists)
writeClkSlewLimit("-data_path ", "-rise ", clk, rise_data_limit);
if (fall_data_exists) {
writeClkSlewLimit("-data_path ", "-fall ", clk, fall_data_limit);
}
}
}
}
}
void
WriteSdc::writeClkSlewLimit(const char *clk_data,
const char *rise_fall,
const Clock *clk,
float limit) const
{
fprintf(stream_, "set_max_transition %s%s", clk_data, rise_fall);
writeTime(limit);
fprintf(stream_, " ");
writeGetClock(clk);
fprintf(stream_, "\n");
}
void
WriteSdc::writeCapLimits() const
{
writeCapLimits(MinMax::min(), "set_min_capacitance");
writeCapLimits(MinMax::max(), "set_max_capacitance");
}
void
WriteSdc::writeCapLimits(const MinMax *min_max,
const char *cmd) const
{
float cap;
bool exists;
sdc_->capacitanceLimit(cell_, min_max, cap, exists);
if (exists) {
fprintf(stream_, "%s ", cmd);
writeCapacitance(cap);
fprintf(stream_, " [current_design]\n");
}
PortCapLimitMap::Iterator port_iter(sdc_->port_cap_limit_map_);
while (port_iter.hasNext()) {
Port *port;
MinMaxFloatValues values;
port_iter.next(port, values);
float cap;
bool exists;
values.value(min_max, cap, exists);
if (exists) {
fprintf(stream_, "%s ", cmd);
writeCapacitance(cap);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
}
PinCapLimitMap::Iterator pin_iter(sdc_->pin_cap_limit_map_);
while (pin_iter.hasNext()) {
Pin *pin;
MinMaxFloatValues values;
pin_iter.next(pin, values);
float cap;
bool exists;
values.value(min_max, cap, exists);
if (exists) {
fprintf(stream_, "%s ", cmd);
writeCapacitance(cap);
fprintf(stream_, " ");
writeGetPin(pin);
fprintf(stream_, "\n");
}
}
}
void
WriteSdc::writeMaxArea() const
{
float max_area = sdc_->maxArea();
if (max_area > 0.0) {
fprintf(stream_, "set_max_area ");
writeFloat(max_area);
fprintf(stream_, "\n");
}
}
void
WriteSdc::writeFanoutLimits() const
{
writeFanoutLimits(MinMax::min(), "set_min_fanout");
writeFanoutLimits(MinMax::max(), "set_max_fanout");
}
void
WriteSdc::writeFanoutLimits(const MinMax *min_max,
const char *cmd) const
{
float fanout;
bool exists;
sdc_->fanoutLimit(cell_, min_max, fanout, exists);
if (exists) {
fprintf(stream_, "%s ", cmd);
writeFloat(fanout);
fprintf(stream_, " [current_design]\n");
}
else {
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
sdc_->fanoutLimit(port, min_max, fanout, exists);
if (exists) {
fprintf(stream_, "%s ", cmd);
writeFloat(fanout);
fprintf(stream_, " ");
writeGetPort(port);
fprintf(stream_, "\n");
}
}
delete port_iter;
}
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeVariables() const
{
if (sdc_->propagateAllClocks()) {
if (native_)
fprintf(stream_, "set sta_propagate_all_clocks 1\n");
else
fprintf(stream_, "set timing_all_clocks_propagated true\n");
}
if (sdc_->presetClrArcsEnabled()) {
if (native_)
fprintf(stream_, "set sta_preset_clear_arcs_enabled 1\n");
else
fprintf(stream_, "set timing_enable_preset_clear_arcs true\n");
}
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeGetTimingArcsOfOjbects(LibertyCell *cell) const
{
fprintf(stream_, "[%s -of_objects ", getTimingArcsCmd());
writeGetLibCell(cell);
fprintf(stream_, "]");
}
void
WriteSdc::writeGetTimingArcs(Edge *edge) const
{
writeGetTimingArcs(edge, NULL);
}
void
WriteSdc::writeGetTimingArcs(Edge *edge,
const char *filter) const
{
fprintf(stream_, "[%s -from ", getTimingArcsCmd());
Vertex *from_vertex = edge->from(graph_);
writeGetPin(from_vertex->pin());
fprintf(stream_, " -to ");
Vertex *to_vertex = edge->to(graph_);
writeGetPin(to_vertex->pin());
if (filter)
fprintf(stream_, " -filter {%s}", filter);
fprintf(stream_, "]");
}
const char *
WriteSdc::getTimingArcsCmd() const
{
return native_ ? "get_timing_edges" : "get_timing_arcs";
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeGetLibCell(const LibertyCell *cell) const
{
fprintf(stream_, "[get_lib_cells {%s/%s}]",
cell->libertyLibrary()->name(),
cell->name());
}
void
WriteSdc::writeGetLibPin(const LibertyPort *port) const
{
LibertyCell *cell = port->libertyCell();
LibertyLibrary *lib = cell->libertyLibrary();
fprintf(stream_, "[get_lib_pins {%s/%s/%s}]",
lib->name(),
cell->name(),
port->name());
}
void
WriteSdc::writeGetClocks(ClockSet *clks) const
{
bool first = true;
bool multiple = clks->size() > 1;
if (multiple)
fprintf(stream_, "[list ");
writeGetClocks(clks, multiple, first);
if (multiple)
fprintf(stream_, "]");
}
void
WriteSdc::writeGetClocks(ClockSet *clks,
bool multiple,
bool &first) const
{
ClockSeq clks1;
sortClockSet(clks, clks1);
ClockSeq::Iterator clk_iter(clks1);
while (clk_iter.hasNext()) {
Clock *clk = clk_iter.next();
if (multiple && !first)
fprintf(stream_, "\\\n ");
writeGetClock(clk);
first = false;
}
}
void
WriteSdc::writeGetClock(const Clock *clk) const
{
fprintf(stream_, "[get_clocks {%s}]",
clk->name());
}
void
WriteSdc::writeGetPort(const Port *port) const
{
fprintf(stream_, "[get_ports {%s}]", sdc_network_->name(port));
}
void
WriteSdc::writeGetPins(PinSet *pins) const
{
PinSeq pins1;
sortPinSet(pins, sdc_network_, pins1);
writeGetPins(&pins1);
}
void
WriteSdc::writeGetPins(PinSeq *pins) const
{
bool multiple = pins->size() > 1;
if (multiple)
fprintf(stream_, "[list ");
PinSeq::Iterator pin_iter(pins);
bool first = true;
while (pin_iter.hasNext()) {
Pin *pin = pin_iter.next();
if (multiple && !first)
fprintf(stream_, "\\\n ");
writeGetPin(pin);
first = false;
}
if (multiple)
fprintf(stream_, "]");
}
void
WriteSdc::writeGetPin(const Pin *pin) const
{
if (sdc_network_->instance(pin) == instance_)
fprintf(stream_, "[get_ports {%s}]", sdc_network_->portName(pin));
else
fprintf(stream_, "[get_pins {%s}]", pathName(pin));
}
void
WriteSdc::writeGetNet(const Net *net) const
{
fprintf(stream_, "[get_nets {%s}]", pathName(net));
}
void
WriteSdc::writeGetInstance(const Instance *inst) const
{
fprintf(stream_, "[get_cells {%s}]", pathName(inst));
}
const char *
WriteSdc::pathName(const Pin *pin) const
{
const char *pin_path = sdc_network_->pathName(pin);
if (top_instance_)
return pin_path;
else
return pin_path + instance_name_length_ + 1;
}
const char *
WriteSdc::pathName(const Net *net) const
{
const char *net_path = sdc_network_->pathName(net);
if (top_instance_)
return net_path;
else
return net_path + instance_name_length_ + 1;
}
const char *
WriteSdc::pathName(const Instance *inst) const
{
const char *inst_path = sdc_network_->pathName(inst);
if (top_instance_)
return inst_path;
else
return inst_path + instance_name_length_ + 1;
}
void
WriteSdc::writeCommentSection(const char *line) const
{
writeCommentSeparator();
fprintf(stream_, "# %s\n", line);
writeCommentSeparator();
}
void
WriteSdc::writeCommentSeparator() const
{
fprintf(stream_, "###############################################################################\n");
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeRiseFallMinMaxTimeCmd(const char *sdc_cmd,
RiseFallMinMax *values,
WriteSdcObject &write_object) const
{
writeRiseFallMinMaxCmd(sdc_cmd, values, units_->timeUnit()->scale(),
write_object);
}
void
WriteSdc::writeRiseFallMinMaxCapCmd(const char *sdc_cmd,
RiseFallMinMax *values,
WriteSdcObject &write_object) const
{
writeRiseFallMinMaxCmd(sdc_cmd, values, units_->capacitanceUnit()->scale(),
write_object);
}
void
WriteSdc::writeRiseFallMinMaxCmd(const char *sdc_cmd,
RiseFallMinMax *values,
float scale,
WriteSdcObject &write_object) const
{
float fall_min, fall_max, rise_min, rise_max;
bool fall_min_exists, fall_max_exists, rise_min_exists, rise_max_exists;
values->value(TransRiseFall::fall(), MinMax::min(),
fall_min, fall_min_exists);
values->value(TransRiseFall::fall(), MinMax::max(),
fall_max, fall_max_exists);
values->value(TransRiseFall::rise(), MinMax::min(),
rise_min, rise_min_exists);
values->value(TransRiseFall::rise(), MinMax::max(),
rise_max, rise_max_exists);
if (fall_min_exists && fall_max_exists
&& rise_min_exists && rise_max_exists) {
if (fall_min == rise_min
&& rise_max == rise_min
&& fall_max == rise_min) {
// rise/fall/min/max match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
TransRiseFallBoth::riseFall(), MinMaxAll::all(),
write_object);
}
else if (rise_min == fall_min
&& rise_max == fall_max) {
// rise/fall match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
TransRiseFallBoth::riseFall(), MinMaxAll::min(),
write_object);
writeRiseFallMinMaxCmd(sdc_cmd, rise_max, scale,
TransRiseFallBoth::riseFall(), MinMaxAll::max(),
write_object);
}
else if (rise_min == rise_max
&& fall_min == fall_max) {
// min/max match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
TransRiseFallBoth::rise(), MinMaxAll::all(),
write_object);
writeRiseFallMinMaxCmd(sdc_cmd, fall_min, scale,
TransRiseFallBoth::fall(), MinMaxAll::all(),
write_object);
}
}
else {
if (rise_min_exists)
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
TransRiseFallBoth::rise(), MinMaxAll::min(),
write_object);
if (rise_max_exists)
writeRiseFallMinMaxCmd(sdc_cmd, rise_max, scale,
TransRiseFallBoth::rise(), MinMaxAll::max(),
write_object);
if (fall_min_exists)
writeRiseFallMinMaxCmd(sdc_cmd, fall_min, scale,
TransRiseFallBoth::fall(), MinMaxAll::min(),
write_object);
if (fall_max_exists)
writeRiseFallMinMaxCmd(sdc_cmd, fall_max, scale,
TransRiseFallBoth::fall(), MinMaxAll::max(),
write_object);
}
}
void
WriteSdc::writeRiseFallMinMaxCmd(const char *sdc_cmd,
float value,
float scale,
const TransRiseFallBoth *tr,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
{
fprintf(stream_, "%s%s%s ",
sdc_cmd,
transRiseFallFlag(tr),
minMaxFlag(min_max));
writeFloat(value / scale);
fprintf(stream_, " ");
write_object.write();
fprintf(stream_, "\n");
}
void
WriteSdc::writeClockKey(const Clock *clk) const
{
fprintf(stream_, " -clock ");
writeGetClock(clk);
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeMinMaxFloatValuesCmd(const char *sdc_cmd,
MinMaxFloatValues *values,
float scale,
WriteSdcObject &write_object) const
{
float min, max;
bool min_exists, max_exists;
values->value(MinMax::min(), min, min_exists);
values->value(MinMax::max(), max, max_exists);
if (min_exists && max_exists
&& min == max) {
// min/max match.
writeMinMaxFloatCmd(sdc_cmd, min, scale, MinMaxAll::all(), write_object);
}
else {
if (min_exists)
writeMinMaxFloatCmd(sdc_cmd, min, scale, MinMaxAll::min(), write_object);
if (max_exists)
writeMinMaxFloatCmd(sdc_cmd, max, scale, MinMaxAll::max(), write_object);
}
}
void
WriteSdc::writeMinMaxFloatCmd(const char *sdc_cmd,
float value,
float scale,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
{
fprintf(stream_, "%s%s ",
sdc_cmd,
minMaxFlag(min_max));
writeFloat(value / scale);
fprintf(stream_, " ");
write_object.write();
fprintf(stream_, "\n");
}
void
WriteSdc::writeMinMaxIntValuesCmd(const char *sdc_cmd,
MinMaxIntValues *values,
WriteSdcObject &write_object) const
{
int min, max;
bool min_exists, max_exists;
values->value(MinMax::min(), min, min_exists);
values->value(MinMax::max(), max, max_exists);
if (min_exists && max_exists
&& min == max) {
// min/max match.
writeMinMaxIntCmd(sdc_cmd, min, MinMaxAll::all(), write_object);
}
else {
if (min_exists)
writeMinMaxIntCmd(sdc_cmd, min, MinMaxAll::min(), write_object);
if (max_exists)
writeMinMaxIntCmd(sdc_cmd, max, MinMaxAll::max(), write_object);
}
}
void
WriteSdc::writeMinMaxIntCmd(const char *sdc_cmd,
int value,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
{
fprintf(stream_, "%s%s ",
sdc_cmd,
minMaxFlag(min_max));
fprintf(stream_, "%d ", value);
write_object.write();
fprintf(stream_, "\n");
}
////////////////////////////////////////////////////////////////
float
WriteSdc::scaleTime(float time) const
{
return time / units_->timeUnit()->scale();
}
float
WriteSdc::scaleCapacitance(float cap) const
{
return cap / units_->capacitanceUnit()->scale();
}
float
WriteSdc::scaleResistance(float res) const
{
return res / units_->resistanceUnit()->scale();
}
void
WriteSdc::writeFloat(float value) const
{
fprintf(stream_, "%.*f", digits_, value);
}
void
WriteSdc::writeTime(float time) const
{
fprintf(stream_, "%.*f", digits_, scaleTime(time));
}
void
WriteSdc::writeCapacitance(float cap) const
{
fprintf(stream_, "%.*f", digits_, scaleCapacitance(cap));
}
void
WriteSdc::writeResistance(float res) const
{
fprintf(stream_, "%.*f", digits_, scaleResistance(res));
}
void
WriteSdc::writeFloatSeq(FloatSeq *floats,
float scale) const
{
fprintf(stream_, "{");
FloatSeq::ConstIterator iter(floats);
bool first = true;
while (iter.hasNext()) {
float flt = iter.next();
if (!first)
fprintf(stream_, " ");
writeFloat(flt * scale);
first = false;
}
fprintf(stream_, "}");
}
void
WriteSdc::writeIntSeq(IntSeq *ints) const
{
fprintf(stream_, "{");
IntSeq::ConstIterator iter(ints);
bool first = true;
while (iter.hasNext()) {
int i = iter.next();
if (!first)
fprintf(stream_, " ");
fprintf(stream_, "%d", i);
first = false;
}
fprintf(stream_, "}");
}
////////////////////////////////////////////////////////////////
static const char *
transRiseFallFlag(const TransRiseFall *tr)
{
return (tr == TransRiseFall::rise()) ? "-rise" : "-fall";
}
static const char *
transRiseFallFlag(const TransRiseFallBoth *tr)
{
if (tr == TransRiseFallBoth::rise())
return " -rise";
else if (tr == TransRiseFallBoth::fall())
return " -fall";
else if (tr == TransRiseFallBoth::riseFall())
return "";
else {
internalError("unknown transition");
}
return NULL;
}
static const char *
minMaxFlag(const MinMaxAll *min_max)
{
if (min_max == MinMaxAll::all())
return "";
else if (min_max == MinMaxAll::min())
return " -min";
else if (min_max == MinMaxAll::max())
return " -max";
else {
internalError("unknown MinMaxAll");
return NULL;
}
}
static const char *
minMaxFlag(const MinMax *min_max)
{
if (min_max == MinMax::min())
return " -min";
else if (min_max == MinMax::max())
return " -max";
else {
internalError("unknown MinMax");
return NULL;
}
}
static const char *
earlyLateFlag(const MinMax *early_late)
{
if (early_late == MinMax::min())
return "-early";
else if (early_late == MinMax::max())
return "-late";
else {
internalError("unknown EarlyLate");
return NULL;
}
}
void
WriteSdc::writeSetupHoldFlag(const MinMaxAll *min_max) const
{
if (min_max == MinMaxAll::min())
fprintf(stream_, " -hold");
else if (min_max == MinMaxAll::max())
fprintf(stream_, " -setup");
}
static const char *
setupHoldFlag(const MinMax *min_max)
{
if (min_max == MinMax::min())
return " -hold";
else if (min_max == MinMax::max())
return " -setup";
else {
internalError("unknown MinMax");
return NULL;
}
}
void
WriteSdc::writeCmdComment(SdcCmdComment *cmd) const
{
const char *comment = cmd->comment();
if (comment) {
fprintf(stream_, " -comment {%s}", comment);
}
}
} // namespace