Files
OpenSTA/sdc/WriteSdc.cc
T

2860 lines
79 KiB
C++
Raw Normal View History

2018-09-28 08:54:21 -07:00
// OpenSTA, Static Timing Analyzer
2026-03-10 13:21:17 -07:00
// Copyright (c) 2026, Parallax Software, Inc.
2018-09-28 08:54:21 -07: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
2022-01-04 10:17:08 -07:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2018-09-28 08:54:21 -07:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
2022-01-04 10:17:08 -07:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2025-01-21 18:54:33 -07:00
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
2018-09-28 08:54:21 -07:00
2020-04-05 14:53:44 -07:00
#include "WriteSdc.hh"
2020-04-05 11:35:51 -07:00
2018-09-28 08:54:21 -07:00
#include <algorithm>
2023-06-15 08:59:56 -07:00
#include <ctime>
2026-01-03 16:59:35 -08:00
#include <set>
2026-03-02 12:13:13 -08:00
#include <string>
2026-03-28 19:13:35 -07:00
#include <string_view>
2026-04-15 09:38:10 -07:00
#include <vector>
2020-04-05 11:35:51 -07:00
2026-04-15 09:38:10 -07:00
#include "ClockGroups.hh"
#include "ClockInsertion.hh"
#include "ClockLatency.hh"
2026-01-03 16:59:35 -08:00
#include "ContainerHelpers.hh"
2026-04-15 09:38:10 -07:00
#include "DataCheck.hh"
#include "DeratingFactors.hh"
#include "DisabledPorts.hh"
2020-04-05 14:53:44 -07:00
#include "Error.hh"
2026-04-15 09:38:10 -07:00
#include "ExceptionPath.hh"
#include "Format.hh"
#include "Fuzzy.hh"
#include "Graph.hh"
#include "GraphCmp.hh"
#include "InputDrive.hh"
2020-04-05 14:53:44 -07:00
#include "Liberty.hh"
#include "Network.hh"
#include "NetworkCmp.hh"
#include "PortDelay.hh"
2026-04-15 09:38:10 -07:00
#include "PortDirection.hh"
2020-04-05 14:53:44 -07:00
#include "PortExtCap.hh"
2026-04-15 09:38:10 -07:00
#include "Report.hh"
#include "RiseFallValues.hh"
#include "Scene.hh"
2020-04-05 14:53:44 -07:00
#include "Sdc.hh"
#include "StaState.hh"
2026-04-15 09:38:10 -07:00
#include "Transition.hh"
#include "Units.hh"
2025-04-09 16:35:15 -07:00
#include "Variables.hh"
2026-04-15 09:38:10 -07:00
#include "Wireload.hh"
2021-12-06 16:36:01 -07:00
#include "WriteSdcPvt.hh"
2026-04-15 09:38:10 -07:00
#include "Zlib.hh"
2018-09-28 08:54:21 -07:00
namespace sta {
2026-04-15 09:38:10 -07:00
using ClockSenseSet = std::set<ClockSense*>;
using ClockSenseSeq = std::vector<ClockSense*>;
2018-09-28 08:54:21 -07:00
2026-03-28 19:13:35 -07:00
static std::string_view
2019-11-11 15:30:19 -07:00
transRiseFallFlag(const RiseFall *rf);
2026-03-28 19:13:35 -07:00
static std::string_view
2019-11-11 15:30:19 -07:00
transRiseFallFlag(const RiseFallBoth *rf);
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
minMaxFlag(const MinMaxAll *min_max);
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
minMaxFlag(const MinMax *min_max);
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
earlyLateFlag(const MinMax *early_late);
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
setupHoldFlag(const MinMax *min_max);
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
timingDerateTypeKeyword(TimingDerateType type);
////////////////////////////////////////////////////////////////
class WriteSdcObject
{
public:
2026-04-15 09:38:10 -07:00
WriteSdcObject() = default;
2026-04-13 14:58:16 -07:00
virtual ~WriteSdcObject() = default;
2018-09-28 08:54:21 -07:00
virtual void write() const = 0;
};
class WriteGetPort : public WriteSdcObject
{
public:
WriteGetPort(const Port *port,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Port *port_;
const WriteSdc *writer_;
};
WriteGetPort::WriteGetPort(const Port *port,
2021-11-15 07:31:29 -07:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
port_(port),
writer_(writer)
{
}
void
WriteGetPort::write() const
{
writer_->writeGetPort(port_);
}
class WriteGetPinAndClkKey : public WriteSdcObject
{
public:
WriteGetPinAndClkKey(const Pin *pin,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr,
const Clock *clk,
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Pin *pin_;
2019-10-25 08:51:59 -07:00
bool map_hpin_to_drvr_;
2018-09-28 08:54:21 -07:00
const Clock *clk_;
const WriteSdc *writer_;
};
WriteGetPinAndClkKey::WriteGetPinAndClkKey(const Pin *pin,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr,
const Clock *clk,
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
pin_(pin),
2019-10-25 08:51:59 -07:00
map_hpin_to_drvr_(map_hpin_to_drvr),
2018-09-28 08:54:21 -07:00
clk_(clk),
writer_(writer)
{
}
void
WriteGetPinAndClkKey::write() const
{
writer_->writeClockKey(clk_);
2026-03-15 14:35:24 -07:00
sta::print(writer_->stream(), " ");
2019-10-25 08:51:59 -07:00
writer_->writeGetPin(pin_, map_hpin_to_drvr_);
2018-09-28 08:54:21 -07:00
}
class WriteGetPin : public WriteSdcObject
{
public:
WriteGetPin(const Pin *pin,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr,
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Pin *pin_;
2019-10-25 08:51:59 -07:00
bool map_hpin_to_drvr_;
2018-09-28 08:54:21 -07:00
const WriteSdc *writer_;
};
WriteGetPin::WriteGetPin(const Pin *pin,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr,
2021-11-15 07:31:29 -07:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
pin_(pin),
2019-10-25 08:51:59 -07:00
map_hpin_to_drvr_(map_hpin_to_drvr),
2018-09-28 08:54:21 -07:00
writer_(writer)
{
}
void
WriteGetPin::write() const
{
2019-10-25 08:51:59 -07:00
writer_->writeGetPin(pin_, map_hpin_to_drvr_);
2018-09-28 08:54:21 -07:00
}
class WriteGetNet : public WriteSdcObject
{
public:
WriteGetNet(const Net *net,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Net *net_;
const WriteSdc *writer_;
};
WriteGetNet::WriteGetNet(const Net *net,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
net_(net),
writer_(writer)
{
}
void
WriteGetNet::write() const
{
writer_->writeGetNet(net_);
}
class WriteGetInstance : public WriteSdcObject
{
public:
WriteGetInstance(const Instance *inst,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Instance *inst_;
const WriteSdc *writer_;
};
WriteGetInstance::WriteGetInstance(const Instance *inst,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
inst_(inst),
writer_(writer)
{
}
void
WriteGetInstance::write() const
{
writer_->writeGetInstance(inst_);
}
class WriteGetLibCell : public WriteSdcObject
{
public:
WriteGetLibCell(const LibertyCell *cell,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const LibertyCell *cell_;
const WriteSdc *writer_;
};
WriteGetLibCell::WriteGetLibCell(const LibertyCell *cell,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
cell_(cell),
writer_(writer)
{
}
void
WriteGetLibCell::write() const
{
writer_->writeGetLibCell(cell_);
}
class WriteGetClock : public WriteSdcObject
{
public:
WriteGetClock(const Clock *clk,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer);
2026-04-15 09:38:10 -07:00
void write() const override;
2018-09-28 08:54:21 -07:00
private:
const Clock *clk_;
const WriteSdc *writer_;
};
WriteGetClock::WriteGetClock(const Clock *clk,
2026-01-03 16:59:35 -08:00
const WriteSdc *writer) :
2018-09-28 08:54:21 -07:00
clk_(clk),
writer_(writer)
{
}
void
WriteGetClock::write() const
{
writer_->writeGetClock(clk_);
}
////////////////////////////////////////////////////////////////
void
2026-01-03 16:59:35 -08:00
writeSdc(const Sdc *sdc,
Instance *instance,
2026-03-28 19:13:35 -07:00
std::string_view filename,
std::string_view creator,
2026-01-03 16:59:35 -08:00
bool map_hpins,
bool native,
int digits,
2021-11-15 07:31:29 -07:00
bool gzip,
2026-01-03 16:59:35 -08:00
bool no_timestamp)
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
WriteSdc writer(sdc, instance, creator, map_hpins, native,
digits, no_timestamp);
2021-11-15 07:36:41 -07:00
writer.write(filename, gzip);
2018-09-28 08:54:21 -07:00
}
2026-01-03 16:59:35 -08:00
WriteSdc::WriteSdc(const Sdc *sdc,
Instance *instance,
2026-03-28 19:13:35 -07:00
std::string_view creator,
2026-01-03 16:59:35 -08:00
bool map_hpins,
bool native,
int digits,
bool no_timestamp) :
2018-09-28 08:54:21 -07:00
StaState(sdc),
2026-01-03 16:59:35 -08:00
sdc_(sdc),
2018-09-28 08:54:21 -07:00
instance_(instance),
creator_(creator),
2019-10-25 08:51:59 -07:00
map_hpins_(map_hpins),
native_(native),
2018-09-28 08:54:21 -07:00
digits_(digits),
no_timestamp_(no_timestamp),
top_instance_(instance == sdc_network_->topInstance()),
2026-03-28 19:13:35 -07:00
instance_name_length_(sdc_network_->pathName(instance).size()),
2018-09-28 08:54:21 -07:00
cell_(sdc_network_->cell(instance))
{
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::write(std::string_view filename,
2021-11-15 07:36:41 -07:00
bool gzip)
2018-09-28 08:54:21 -07:00
{
2021-11-15 07:36:41 -07:00
openFile(filename, gzip);
2018-09-28 08:54:21 -07:00
writeHeader();
writeTiming();
writeEnvironment();
writeDesignRules();
writeVariables();
closeFile();
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::openFile(std::string_view filename,
2021-11-15 07:36:41 -07:00
bool gzip)
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string filename_str(filename);
stream_ = gzopen(filename_str.c_str(), gzip ? "wb" : "wT");
2019-03-12 17:25:53 -07:00
if (stream_ == nullptr)
2021-11-15 07:36:41 -07:00
throw FileNotWritable(filename);
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::closeFile()
{
2021-11-15 07:31:29 -07:00
gzclose(stream_);
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeHeader() const
{
writeCommentSeparator();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "# Created by {}\n", creator_);
2018-09-28 08:54:21 -07:00
if (!no_timestamp_) {
time_t now;
time(&now);
2026-03-28 19:13:35 -07:00
std::string time_str(ctime(&now));
if (!time_str.empty() && time_str.back() == '\n')
time_str.pop_back();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "# {}\n", time_str);
2018-09-28 08:54:21 -07:00
}
writeCommentSeparator();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "current_design {}\n", sdc_network_->name(cell_));
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
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.
2024-06-27 13:57:58 -07:00
for (const auto clk : sdc_->clocks_) {
2018-09-28 08:54:21 -07:00
if (clk->isGenerated())
writeGeneratedClock(clk);
else
writeClock(clk);
writeClockSlews(clk);
writeClockUncertainty(clk);
if (clk->isPropagated()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_propagated_clock ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
}
void
WriteSdc::writeClock(Clock *clk) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "create_clock -name {}",
clk->name());
2018-09-28 08:54:21 -07:00
if (clk->addToPins())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -add");
sta::print(stream_, " -period ");
2021-05-05 23:12:53 -07:00
float period = clk->period();
writeTime(period);
2026-04-16 18:42:26 -07:00
const FloatSeq &waveform = clk->waveform();
if (!(waveform.size() == 2
&& waveform[0] == 0.0
&& fuzzyEqual(waveform[1], period / 2.0))) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -waveform ");
2021-05-05 23:12:53 -07:00
writeFloatSeq(waveform, scaleTime(1.0));
}
2018-09-28 08:54:21 -07:00
writeCmdComment(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeClockPins(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGeneratedClock(Clock *clk) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "create_generated_clock -name {}",
clk->name());
2018-09-28 08:54:21 -07:00
if (clk->addToPins())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -add");
sta::print(stream_, " -source ");
2019-10-25 08:51:59 -07:00
writeGetPin(clk->srcPin(), true);
2018-09-28 08:54:21 -07:00
Clock *master = clk->masterClk();
if (master && !clk->masterClkInfered()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -master_clock ");
2018-09-28 08:54:21 -07:00
writeGetClock(master);
}
if (clk->combinational())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -combinational");
2018-09-28 08:54:21 -07:00
int divide_by = clk->divideBy();
if (divide_by != 0)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -divide_by {}", divide_by);
2018-09-28 08:54:21 -07:00
int multiply_by = clk->multiplyBy();
if (multiply_by != 0)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -multiply_by {}", multiply_by);
2018-09-28 08:54:21 -07:00
float duty_cycle = clk->dutyCycle();
if (duty_cycle != 0.0) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -duty_cycle ");
2018-09-28 08:54:21 -07:00
writeFloat(duty_cycle);
}
if (clk->invert())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -invert");
2026-04-16 18:42:26 -07:00
const IntSeq &edges = clk->edges();
if (!edges.empty()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -edges ");
2018-09-28 08:54:21 -07:00
writeIntSeq(edges);
2026-04-16 18:42:26 -07:00
const FloatSeq &edge_shifts = clk->edgeShifts();
if (!edge_shifts.empty()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -edge_shift ");
2018-09-28 08:54:21 -07:00
writeFloatSeq(edge_shifts, scaleTime(1.0));
}
}
writeCmdComment(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeClockPins(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeClockPins(const Clock *clk) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const PinSet &pins = clk->pins();
2018-09-28 08:54:21 -07:00
if (!pins.empty()) {
if (pins.size() > 1)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2019-10-25 08:51:59 -07:00
writeGetPins(&pins, true);
2018-09-28 08:54:21 -07:00
}
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeClockSlews(const Clock *clk) const
2018-09-28 08:54:21 -07:00
{
WriteGetClock write_clk(clk, this);
2023-01-19 11:23:45 -07:00
const RiseFallMinMax slews = clk->slews();
if (slews.hasValue())
writeRiseFallMinMaxTimeCmd("set_clock_transition", &slews, write_clk);
2018-09-28 08:54:21 -07:00
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeClockUncertainty(const Clock *clk) const
2018-09-28 08:54:21 -07:00
{
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
2023-01-19 11:23:45 -07:00
WriteSdc::writeClockUncertainty(const Clock *clk,
2026-03-28 19:13:35 -07:00
std::string_view setup_hold,
2026-01-03 16:59:35 -08:00
float value) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_clock_uncertainty {}", setup_hold);
2018-09-28 08:54:21 -07:00
writeTime(value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {}\n", clk->name());
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeClockUncertaintyPins() const
{
2026-01-03 16:59:35 -08:00
for (const auto [pin, uncertainties] : sdc_->pin_clk_uncertainty_map_)
2018-09-28 08:54:21 -07:00
writeClockUncertaintyPin(pin, uncertainties);
}
void
WriteSdc::writeClockUncertaintyPin(const Pin *pin,
2026-01-03 16:59:35 -08:00
ClockUncertainties *uncertainties)
2018-09-28 08:54:21 -07:00
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,
2026-03-28 19:13:35 -07:00
std::string_view setup_hold,
2026-01-03 16:59:35 -08:00
float value) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_clock_uncertainty {}", setup_hold);
2018-09-28 08:54:21 -07:00
writeTime(value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, true);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeClockLatencies() const
{
2026-01-03 16:59:35 -08:00
for (ClockLatency *latency : *sdc_->clockLatencies()) {
2018-09-28 08:54:21 -07:00
const Pin *pin = latency->pin();
const Clock *clk = latency->clock();
if (pin && clk) {
2019-10-25 08:51:59 -07:00
WriteGetPinAndClkKey write_pin(pin, true, clk, this);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
2026-01-03 16:59:35 -08:00
write_pin);
2018-09-28 08:54:21 -07:00
}
else if (pin) {
2019-10-25 08:51:59 -07:00
WriteGetPin write_pin(pin, true, this);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
2026-01-03 16:59:35 -08:00
write_pin);
2018-09-28 08:54:21 -07:00
}
else if (clk) {
WriteGetClock write_clk(clk, this);
writeRiseFallMinMaxTimeCmd("set_clock_latency", latency->delays(),
2026-01-03 16:59:35 -08:00
write_clk);
2018-09-28 08:54:21 -07:00
}
}
}
void
WriteSdc::writeClockInsertions() const
{
2023-01-19 11:23:45 -07:00
for (ClockInsertion *insert : sdc_->clockInsertions()) {
2018-09-28 08:54:21 -07:00
const Pin *pin = insert->pin();
const Clock *clk = insert->clock();
if (pin && clk) {
2019-10-25 08:51:59 -07:00
WriteGetPinAndClkKey write_pin_clk(pin, true, clk, this);
2018-09-28 08:54:21 -07:00
writeClockInsertion(insert, write_pin_clk);
}
else if (pin) {
2019-10-25 08:51:59 -07:00
WriteGetPin write_pin(pin, true, this);
2018-09-28 08:54:21 -07:00
writeClockInsertion(insert, write_pin);
}
else if (clk) {
WriteGetClock write_clk(clk, this);
writeClockInsertion(insert, write_clk);
}
}
}
void
WriteSdc::writeClockInsertion(ClockInsertion *insert,
2026-01-03 16:59:35 -08:00
WriteSdcObject &write_obj) const
2018-09-28 08:54:21 -07:00
{
2018-11-26 09:15:52 -08:00
RiseFallMinMax *early_values = insert->delays(EarlyLate::early());
RiseFallMinMax *late_values = insert->delays(EarlyLate::late());
2018-09-28 08:54:21 -07:00
if (early_values->equal(late_values))
writeRiseFallMinMaxTimeCmd("set_clock_latency -source",
2026-01-03 16:59:35 -08:00
late_values, write_obj);
2018-09-28 08:54:21 -07:00
else {
writeRiseFallMinMaxTimeCmd("set_clock_latency -source -early",
2026-01-03 16:59:35 -08:00
early_values, write_obj);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxTimeCmd("set_clock_latency -source -late",
2026-01-03 16:59:35 -08:00
late_values, write_obj);
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writePropagatedClkPins() const
{
2026-01-03 16:59:35 -08:00
for (const Pin *pin : sdc_->propagated_clk_pins_) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_propagated_clock ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, true);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeInterClockUncertainties() const
{
2026-01-03 16:59:35 -08:00
for (InterClockUncertainty *uncertainty : sdc_->inter_clk_uncertainties_)
2018-09-28 08:54:21 -07:00
writeInterClockUncertainty(uncertainty);
}
void
WriteSdc::
writeInterClockUncertainty(InterClockUncertainty *uncertainty) const
{
const Clock *src_clk = uncertainty->src();
const Clock *tgt_clk = uncertainty->target();
const RiseFallMinMax *src_rise =
2019-11-11 15:30:19 -07:00
uncertainty->uncertainties(RiseFall::rise());
2018-09-28 08:54:21 -07:00
const RiseFallMinMax *src_fall =
2019-11-11 15:30:19 -07:00
uncertainty->uncertainties(RiseFall::fall());
2018-09-28 08:54:21 -07:00
float value;
if (src_rise->equal(src_fall)
&& src_rise->isOneValue(value)) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_clock_uncertainty -from ");
2018-09-28 08:54:21 -07:00
writeGetClock(src_clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -to ");
2018-09-28 08:54:21 -07:00
writeGetClock(tgt_clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeTime(value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
else {
2019-11-11 15:30:19 -07:00
for (auto src_rf : RiseFall::range()) {
for (auto tgt_rf : RiseFall::range()) {
2026-01-03 16:59:35 -08:00
for (auto setup_hold : SetupHold::range()) {
float value;
bool exists;
sdc_->clockUncertainty(src_clk, src_rf, tgt_clk, tgt_rf,
setup_hold, value, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_clock_uncertainty -{}_from ",
src_rf == RiseFall::rise() ? "rise" : "fall");
2026-01-03 16:59:35 -08:00
writeGetClock(uncertainty->src());
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -{}_to ",
tgt_rf == RiseFall::rise() ? "rise" : "fall");
2026-01-03 16:59:35 -08:00
writeGetClock(uncertainty->target());
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {} ",
setupHoldFlag(setup_hold));
2026-01-03 16:59:35 -08:00
writeTime(value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2026-01-03 16:59:35 -08:00
}
}
2018-09-28 08:54:21 -07:00
}
}
}
}
void
WriteSdc::writeInputDelays() const
{
// Sort arrivals by pin and clock name.
PortDelaySeq delays;
2019-10-25 08:51:59 -07:00
for (InputDelay *input_delay : sdc_->inputDelays())
2018-09-28 08:54:21 -07:00
delays.push_back(input_delay);
2019-03-12 17:25:53 -07:00
2018-09-28 08:54:21 -07:00
PortDelayLess port_delay_less(sdc_network_);
sort(delays, port_delay_less);
2019-03-12 17:25:53 -07:00
2026-01-03 16:59:35 -08:00
for (PortDelay *input_delay : delays)
2019-10-25 08:51:59 -07:00
writePortDelay(input_delay, true, "set_input_delay");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeOutputDelays() const
{
// Sort departures by pin and clock name.
PortDelaySeq delays;
2019-10-25 08:51:59 -07:00
for (OutputDelay *output_delay : sdc_->outputDelays())
2018-09-28 08:54:21 -07:00
delays.push_back(output_delay);
2019-03-12 17:25:53 -07:00
2023-01-19 11:23:45 -07:00
sort(delays, PortDelayLess(sdc_network_));
2019-03-12 17:25:53 -07:00
2023-01-19 11:23:45 -07:00
for (PortDelay *output_delay : delays)
2019-10-25 08:51:59 -07:00
writePortDelay(output_delay, false, "set_output_delay");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writePortDelay(PortDelay *port_delay,
2026-01-03 16:59:35 -08:00
bool is_input_delay,
2026-03-28 19:13:35 -07:00
std::string_view sdc_cmd) const
2018-09-28 08:54:21 -07:00
{
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;
2019-11-11 15:30:19 -07:00
delays->value(RiseFall::rise(), MinMax::min(),
2026-01-03 16:59:35 -08:00
rise_min, rise_min_exists);
2019-11-11 15:30:19 -07:00
delays->value(RiseFall::rise(), MinMax::max(),
2026-01-03 16:59:35 -08:00
rise_max, rise_max_exists);
2019-11-11 15:30:19 -07:00
delays->value(RiseFall::fall(), MinMax::min(),
2026-01-03 16:59:35 -08:00
fall_min, fall_min_exists);
2019-11-11 15:30:19 -07:00
delays->value(RiseFall::fall(), MinMax::max(),
2026-01-03 16:59:35 -08:00
fall_max, fall_max_exists);
2018-09-28 08:54:21 -07:00
// 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)
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::all(), sdc_cmd);
2018-09-28 08:54:21 -07:00
else if (rise_min_exists
2026-01-03 16:59:35 -08:00
&& rise_max_exists
&& rise_max == rise_min
&& fall_min_exists
&& fall_max_exists
&& fall_min == fall_max) {
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::all(), sdc_cmd);
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, fall_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::all(), sdc_cmd);
2018-09-28 08:54:21 -07:00
}
else if (rise_min_exists
2026-01-03 16:59:35 -08:00
&& fall_min_exists
&& rise_min == fall_min
&& rise_max_exists
&& fall_max_exists
&& rise_max == fall_max) {
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::min(), sdc_cmd);
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_max,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::max(), sdc_cmd);
2018-09-28 08:54:21 -07:00
}
else {
if (rise_min_exists)
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::min(), sdc_cmd);
2018-09-28 08:54:21 -07:00
if (rise_max_exists)
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, rise_max,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::max(), sdc_cmd);
2018-09-28 08:54:21 -07:00
if (fall_min_exists)
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, fall_min,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::min(), sdc_cmd);
2018-09-28 08:54:21 -07:00
if (fall_max_exists)
2019-10-25 08:51:59 -07:00
writePortDelay(port_delay, is_input_delay, fall_max,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::max(), sdc_cmd);
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writePortDelay(PortDelay *port_delay,
2026-01-03 16:59:35 -08:00
bool is_input_delay,
float delay,
const RiseFallBoth *rf,
const MinMaxAll *min_max,
2026-03-28 19:13:35 -07:00
std::string_view sdc_cmd) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", sdc_cmd);
2018-09-28 08:54:21 -07:00
writeTime(delay);
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = port_delay->clkEdge();
2018-09-28 08:54:21 -07:00
if (clk_edge) {
writeClockKey(clk_edge->clock());
2019-11-11 15:30:19 -07:00
if (clk_edge->transition() == RiseFall::fall())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -clock_fall");
2018-09-28 08:54:21 -07:00
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}{} -add_delay ",
transRiseFallFlag(rf),
minMaxFlag(min_max));
2023-01-19 11:23:45 -07:00
const Pin *ref_pin = port_delay->refPin();
2018-09-28 08:54:21 -07:00
if (ref_pin) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-reference_pin ");
2019-10-25 08:51:59 -07:00
writeGetPin(ref_pin, true);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
}
2019-10-25 08:51:59 -07:00
writeGetPin(port_delay->pin(), is_input_delay);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
class PinClockPairNameLess
{
public:
PinClockPairNameLess(const Network *network);
2019-03-12 17:25:53 -07:00
bool operator()(const PinClockPair &pin_clk1,
2026-01-03 16:59:35 -08:00
const PinClockPair &pin_clk2) const;
2018-09-28 08:54:21 -07:00
private:
PinPathNameLess pin_less_;
};
PinClockPairNameLess::PinClockPairNameLess(const Network *network) :
pin_less_(network)
{
}
bool
2019-03-12 17:25:53 -07:00
PinClockPairNameLess::operator()(const PinClockPair &pin_clk1,
2026-01-03 16:59:35 -08:00
const PinClockPair &pin_clk2) const
2018-09-28 08:54:21 -07:00
{
2019-03-12 17:25:53 -07:00
const Pin *pin1 = pin_clk1.first;
const Pin *pin2 = pin_clk2.first;
const Clock *clk1 = pin_clk1.second;
const Clock *clk2 = pin_clk2.second;
2018-09-28 08:54:21 -07:00
return pin_less_(pin1, pin2)
|| (pin1 == pin2
2026-01-03 16:59:35 -08:00
&& ((clk1 == nullptr && clk2)
|| (clk1 && clk2
&& clk1->index() < clk2->index())));
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeClockSenses() const
{
2026-01-03 16:59:35 -08:00
std::vector<PinClockPair> pin_clks;
2024-06-27 13:57:58 -07:00
for (const auto& [pin_clk, sense] : sdc_->clk_sense_map_)
pin_clks.push_back(pin_clk);
2019-03-12 17:25:53 -07:00
2018-09-28 08:54:21 -07:00
// Sort by pin/clk pair so regressions results are stable.
sort(pin_clks, PinClockPairNameLess(sdc_network_));
2019-03-12 17:25:53 -07:00
for (auto pin_clk : pin_clks) {
2018-09-28 08:54:21 -07:00
ClockSense sense;
bool exists;
2026-01-03 16:59:35 -08:00
findKeyValue(sdc_->clk_sense_map_, pin_clk, sense, exists);
2018-09-28 08:54:21 -07:00
if (exists)
writeClockSense(pin_clk, sense);
}
}
void
2019-03-12 17:25:53 -07:00
WriteSdc::writeClockSense(PinClockPair &pin_clk,
2026-01-03 16:59:35 -08:00
ClockSense sense) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view flag;
2019-03-12 17:25:53 -07:00
if (sense == ClockSense::positive)
2018-09-28 08:54:21 -07:00
flag = "-positive";
2019-03-12 17:25:53 -07:00
else if (sense == ClockSense::negative)
2018-09-28 08:54:21 -07:00
flag = "-negative";
2019-03-12 17:25:53 -07:00
else if (sense == ClockSense::stop)
2018-09-28 08:54:21 -07:00
flag = "-stop_propagation";
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_sense -type clock {} ", flag);
2019-03-12 17:25:53 -07:00
const Clock *clk = pin_clk.second;
2018-09-28 08:54:21 -07:00
if (clk) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-clock ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
}
2019-10-25 08:51:59 -07:00
writeGetPin(pin_clk.first, true);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
class ClockGroupLess
{
public:
bool operator()(const ClockGroup *clk_group1,
2026-01-03 16:59:35 -08:00
const ClockGroup *clk_group2) const;
2018-09-28 08:54:21 -07:00
};
bool
ClockGroupLess::operator()(const ClockGroup *clk_group1,
2026-01-03 16:59:35 -08:00
const ClockGroup *clk_group2) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
size_t size1 = clk_group1->size();
size_t size2 = clk_group2->size();
2018-09-28 08:54:21 -07:00
if (size1 < size2)
return true;
else if (size1 > size2)
return false;
else {
2023-01-19 11:23:45 -07:00
ClockSeq clks1;
for (Clock *clk1 : *clk_group1)
clks1.push_back(clk1);
2018-09-28 08:54:21 -07:00
sort(clks1, ClockNameLess());
2023-01-19 11:23:45 -07:00
ClockSeq clks2;
for (Clock *clk2 : *clk_group2)
clks2.push_back(clk2);
2018-09-28 08:54:21 -07:00
sort(clks2, ClockNameLess());
2026-01-03 16:59:35 -08:00
ClockSeq::iterator clk_iter3 = clks1.begin();
ClockSeq::iterator clk_iter4 = clks2.begin();
while (clk_iter3 != clks1.end()
&& clk_iter4 != clks2.end()) {
Clock *clk1 = *clk_iter3++;
Clock *clk2 = *clk_iter4++;
2026-03-28 19:13:35 -07:00
int cmp = clk1->name().compare(clk2->name());
2018-09-28 08:54:21 -07:00
if (cmp < 0)
2026-01-03 16:59:35 -08:00
return true;
2018-09-28 08:54:21 -07:00
else if (cmp > 0)
2026-01-03 16:59:35 -08:00
return false;
2018-09-28 08:54:21 -07:00
}
return false;
}
}
void
WriteSdc::writeClockGroups() const
{
2026-03-15 14:35:24 -07:00
for (const auto &[name, clk_groups] : sdc_->clk_groups_name_map_)
2018-09-28 08:54:21 -07:00
writeClockGroups(clk_groups);
}
void
WriteSdc::writeClockGroups(ClockGroups *clk_groups) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_clock_groups -name {} ", clk_groups->name());
2018-09-28 08:54:21 -07:00
if (clk_groups->logicallyExclusive())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-logically_exclusive \\\n");
2018-09-28 08:54:21 -07:00
else if (clk_groups->physicallyExclusive())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-physically_exclusive \\\n");
2018-09-28 08:54:21 -07:00
else if (clk_groups->asynchronous())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-asynchronous \\\n");
2018-09-28 08:54:21 -07:00
if (clk_groups->allowPaths())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "-allow_paths \\\n");
2026-01-03 16:59:35 -08:00
std::vector<ClockGroup*> groups;
for (ClockGroup *clk_group : *clk_groups->groups())
2018-09-28 08:54:21 -07:00
groups.push_back(clk_group);
sort(groups, ClockGroupLess());
bool first = true;
2026-01-03 16:59:35 -08:00
for (ClockGroup *clk_group : groups) {
2018-09-28 08:54:21 -07:00
if (!first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n");
sta::print(stream_, " -group ");
2023-01-19 11:23:45 -07:00
writeGetClocks(clk_group);
2018-09-28 08:54:21 -07:00
first = false;
}
writeCmdComment(clk_groups);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDisables() const
{
writeDisabledCells();
writeDisabledPorts();
writeDisabledLibPorts();
writeDisabledInstances();
writeDisabledPins();
writeDisabledEdges();
}
void
WriteSdc::writeDisabledCells() const
{
2023-01-19 11:23:45 -07:00
DisabledCellPortsSeq disables = sortByName(sdc_->disabledCellPorts());
for (const DisabledCellPorts *disable : disables) {
const LibertyCell *cell = disable->cell();
2018-09-28 08:54:21 -07:00
if (disable->all()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetLibCell(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
if (disable->fromTo()) {
2023-01-19 11:23:45 -07:00
LibertyPortPairSeq from_tos = sortByName(disable->fromTo());
for (const LibertyPortPair &from_to : from_tos) {
2026-01-03 16:59:35 -08:00
const LibertyPort *from = from_to.first;
const LibertyPort *to = from_to.second;
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -from {{{}}} -to {{{}}} ",
from->name(),
to->name());
2026-01-03 16:59:35 -08:00
writeGetLibCell(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
if (disable->from()) {
2023-01-19 11:23:45 -07:00
LibertyPortSeq from = sortByName(disable->from());
for (const LibertyPort *from_port : from) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -from {{{}}} ",
from_port->name());
2026-01-03 16:59:35 -08:00
writeGetLibCell(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
if (disable->to()) {
2023-01-19 11:23:45 -07:00
LibertyPortSeq to = sortByName(disable->to());
for (const LibertyPort *to_port : to) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -to {{{}}} ",
to_port->name());
2026-01-03 16:59:35 -08:00
writeGetLibCell(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
if (disable->timingArcSets()) {
// The only syntax to disable timing arc sets disables all of the
// cell's timing arc sets.
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetTimingArcsOfOjbects(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
}
void
WriteSdc::writeDisabledPorts() const
{
2023-01-19 11:23:45 -07:00
const PortSeq ports = sortByName(sdc_->disabledPorts(), sdc_network_);
for (const Port *port : ports) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeDisabledLibPorts() const
{
2023-01-19 11:23:45 -07:00
LibertyPortSeq ports = sortByName(sdc_->disabledLibPorts());
for (LibertyPort *port : ports) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetLibPin(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeDisabledInstances() const
{
2023-01-19 11:23:45 -07:00
DisabledInstancePortsSeq disables = sortByPathName(sdc_->disabledInstancePorts(),
sdc_network_);
for (DisabledInstancePorts *disable : disables) {
2018-09-28 08:54:21 -07:00
Instance *inst = disable->instance();
if (disable->all()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetInstance(inst);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
else if (disable->fromTo()) {
2023-01-19 11:23:45 -07:00
LibertyPortPairSeq from_tos = sortByName(disable->fromTo());
for (LibertyPortPair &from_to : from_tos) {
2026-01-03 16:59:35 -08:00
const LibertyPort *from_port = from_to.first;
const LibertyPort *to_port = from_to.second;
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -from {{{}}} -to {{{}}} ",
from_port->name(),
to_port->name());
2026-01-03 16:59:35 -08:00
writeGetInstance(inst);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
if (disable->from()) {
2023-01-19 11:23:45 -07:00
LibertyPortSeq from = sortByName(disable->from());
for (const LibertyPort *from_port : from) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -from {{{}}} ",
from_port->name());
2026-01-03 16:59:35 -08:00
writeGetInstance(inst);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
if (disable->to()) {
2023-01-19 11:23:45 -07:00
LibertyPortSeq to = sortByName(disable->to());
for (const LibertyPort *to_port : to) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing -to {{{}}} ",
to_port->name());
2026-01-03 16:59:35 -08:00
writeGetInstance(inst);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
}
}
void
WriteSdc::writeDisabledPins() const
{
2023-01-19 11:23:45 -07:00
PinSeq pins = sortByPathName(sdc_->disabledPins(), sdc_network_);
for (const Pin *pin : pins) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeDisabledEdges() const
{
EdgeSeq edges;
2023-01-19 11:23:45 -07:00
for (Edge *edge : *sdc_->disabledEdges())
2018-09-28 08:54:21 -07:00
edges.push_back(edge);
sortEdges(&edges, sdc_network_, graph_);
2023-01-19 11:23:45 -07:00
for (Edge *edge : edges) {
2018-09-28 08:54:21 -07:00
EdgeSet matches;
findMatchingEdges(edge, matches);
if (matches.size() == 1)
writeDisabledEdge(edge);
else if (edgeSenseIsUnique(edge, matches))
writeDisabledEdgeSense(edge);
}
}
void
WriteSdc::findMatchingEdges(Edge *edge,
2026-01-03 16:59:35 -08:00
EdgeSet &matches) const
2018-09-28 08:54:21 -07:00
{
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,
2026-01-03 16:59:35 -08:00
EdgeSet &matches) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
for (Edge *match : matches) {
2018-09-28 08:54:21 -07:00
if (match != edge
2026-01-03 16:59:35 -08:00
&& match->sense() == edge->sense())
2018-09-28 08:54:21 -07:00
return false;
}
return true;
}
void
WriteSdc::writeDisabledEdge(Edge *edge) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2018-09-28 08:54:21 -07:00
writeGetTimingArcs(edge);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeDisabledEdgeSense(Edge *edge) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_disable_timing ");
2026-03-28 19:13:35 -07:00
std::string filter = sta::format("sense == {}", to_string(edge->sense()));
writeGetTimingArcs(edge, filter);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeExceptions() const
{
ExceptionPathSeq exceptions;
2025-11-08 13:38:07 -07:00
for (ExceptionPath *exception : sdc_->exceptions())
2023-01-19 11:23:45 -07:00
exceptions.push_back(exception);
sort(exceptions, ExceptionPathLess(network_));
for (ExceptionPath *exception : exceptions) {
2018-09-28 08:54:21 -07:00
if (!exception->isFilter()
2026-01-03 16:59:35 -08:00
&& !exception->isLoop())
2018-09-28 08:54:21 -07:00
writeException(exception);
}
}
void
WriteSdc::writeException(ExceptionPath *exception) const
{
writeExceptionCmd(exception);
if (exception->from())
writeExceptionFrom(exception->from());
if (exception->thrus()) {
2023-01-19 11:23:45 -07:00
for (ExceptionThru *thru : *exception->thrus())
2018-09-28 08:54:21 -07:00
writeExceptionThru(thru);
}
if (exception->to())
writeExceptionTo(exception->to());
writeExceptionValue(exception);
writeCmdComment(exception);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeExceptionCmd(ExceptionPath *exception) const
{
if (exception->isFalse()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_false_path");
2018-09-28 08:54:21 -07:00
writeSetupHoldFlag(exception->minMax());
}
else if (exception->isMultiCycle()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_multicycle_path");
2018-09-28 08:54:21 -07:00
const MinMaxAll *min_max = exception->minMax();
writeSetupHoldFlag(min_max);
if (min_max == MinMaxAll::min()) {
// For hold MCPs default is -start.
if (exception->useEndClk())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -end");
2018-09-28 08:54:21 -07:00
}
else {
// For setup MCPs default is -end.
if (!exception->useEndClk())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -start");
2018-09-28 08:54:21 -07:00
}
}
else if (exception->isPathDelay()) {
if (exception->minMax() == MinMaxAll::max())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_delay");
2018-09-28 08:54:21 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_min_delay");
2018-09-28 08:54:21 -07:00
if (exception->ignoreClkLatency())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -ignore_clock_latency");
2018-09-28 08:54:21 -07:00
}
else if (exception->isGroupPath()) {
if (exception->isDefault())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "group_path -default");
2018-09-28 08:54:21 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "group_path -name {}", exception->name());
2018-09-28 08:54:21 -07:00
}
else
2024-01-07 19:23:53 -07:00
report_->critical(1620, "unknown exception type");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeExceptionValue(ExceptionPath *exception) const
{
if (exception->isMultiCycle())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {}",
exception->pathMultiplier());
2018-09-28 08:54:21 -07:00
else if (exception->isPathDelay()) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeTime(exception->delay());
}
}
void
WriteSdc::writeExceptionFrom(ExceptionFrom *from) const
{
2019-10-25 08:51:59 -07:00
writeExceptionFromTo(from, "from", true);
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeExceptionTo(ExceptionTo *to) const
{
2019-11-11 15:30:19 -07:00
const RiseFallBoth *end_rf = to->endTransition();
if (end_rf != RiseFallBoth::riseFall())
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", transRiseFallFlag(end_rf));
2018-09-28 08:54:21 -07:00
if (to->hasObjects())
2019-10-25 08:51:59 -07:00
writeExceptionFromTo(to, "to", false);
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeExceptionFromTo(ExceptionFromTo *from_to,
2026-03-28 19:13:35 -07:00
std::string_view from_to_key,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
const RiseFallBoth *rf = from_to->transition();
2026-03-28 19:13:35 -07:00
std::string_view rf_prefix = "-";
2019-11-11 15:30:19 -07:00
if (rf == RiseFallBoth::rise())
2021-11-22 07:37:59 -08:00
rf_prefix = "-rise_";
2019-11-11 15:30:19 -07:00
else if (rf == RiseFallBoth::fall())
2021-11-22 07:37:59 -08:00
rf_prefix = "-fall_";
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n {}{} ", rf_prefix, from_to_key);
2018-09-28 08:54:21 -07:00
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)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[list ");
2018-09-28 08:54:21 -07:00
bool first = true;
if (from_to->pins()) {
2023-01-19 11:23:45 -07:00
PinSeq pins = sortByPathName(from_to->pins(), sdc_network_);
for (const Pin *pin : pins) {
2018-09-28 08:54:21 -07:00
if (multi_objs && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, map_hpin_to_drvr);
2018-09-28 08:54:21 -07:00
first = false;
}
}
if (from_to->clks())
writeGetClocks(from_to->clks(), multi_objs, first);
if (from_to->instances()) {
2023-01-19 11:23:45 -07:00
InstanceSeq insts = sortByPathName(from_to->instances(), sdc_network_);
for (const Instance *inst : insts) {
2018-09-28 08:54:21 -07:00
if (multi_objs && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2018-09-28 08:54:21 -07:00
writeGetInstance(inst);
first = false;
}
}
if (multi_objs)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeExceptionThru(ExceptionThru *thru) const
{
2019-11-11 15:30:19 -07:00
const RiseFallBoth *rf = thru->transition();
2026-03-28 19:13:35 -07:00
std::string_view rf_prefix = "-";
2019-11-11 15:30:19 -07:00
if (rf == RiseFallBoth::rise())
2021-11-22 07:37:59 -08:00
rf_prefix = "-rise_";
2019-11-11 15:30:19 -07:00
else if (rf == RiseFallBoth::fall())
2021-11-22 07:37:59 -08:00
rf_prefix = "-fall_";
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n {}through ", rf_prefix);
2019-10-25 08:51:59 -07:00
PinSeq pins;
mapThruHpins(thru, pins);
2018-09-28 08:54:21 -07:00
bool multi_objs =
2019-10-25 08:51:59 -07:00
(pins.size()
2018-09-28 08:54:21 -07:00
+ (thru->nets() ? thru->nets()->size() : 0)
2019-10-25 08:51:59 -07:00
+ (thru->instances() ? thru->instances()->size() : 0)) > 1;
2018-09-28 08:54:21 -07:00
if (multi_objs)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[list ");
2018-09-28 08:54:21 -07:00
bool first = true;
2019-10-25 08:51:59 -07:00
sort(pins, PinPathNameLess(network_));
2023-01-19 11:23:45 -07:00
for (const Pin *pin : pins) {
2019-10-25 08:51:59 -07:00
if (multi_objs && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin);
first = false;
2018-09-28 08:54:21 -07:00
}
2019-10-25 08:51:59 -07:00
2018-09-28 08:54:21 -07:00
if (thru->nets()) {
2023-01-19 11:23:45 -07:00
NetSeq nets = sortByPathName(thru->nets(), sdc_network_);
for (const Net *net : nets) {
2018-09-28 08:54:21 -07:00
if (multi_objs && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2018-09-28 08:54:21 -07:00
writeGetNet(net);
first = false;
}
}
if (thru->instances()) {
2023-01-19 11:23:45 -07:00
InstanceSeq insts = sortByPathName(thru->instances(), sdc_network_);
for (const Instance *inst : insts) {
2018-09-28 08:54:21 -07:00
if (multi_objs && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2018-09-28 08:54:21 -07:00
writeGetInstance(inst);
first = false;
}
}
if (multi_objs)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
2019-10-25 08:51:59 -07:00
void
WriteSdc::mapThruHpins(ExceptionThru *thru,
2026-01-03 16:59:35 -08:00
PinSeq &pins) const
2019-10-25 08:51:59 -07:00
{
if (thru->pins()) {
2023-01-19 11:23:45 -07:00
for (const Pin *pin : *thru->pins()) {
2019-10-25 08:51:59 -07:00
// Map hierarical pins to load pins outside of outputs or inside of inputs.
if (network_->isHierarchical(pin)) {
2026-01-03 16:59:35 -08:00
Instance *hinst = network_->instance(pin);
bool hpin_is_output = network_->direction(pin)->isAnyOutput();
PinConnectedPinIterator *cpin_iter = network_->connectedPinIterator(pin);
while (cpin_iter->hasNext()) {
const Pin *cpin = cpin_iter->next();
if (network_->isLoad(cpin)
&& ((hpin_is_output
&& !network_->isInside(network_->instance(cpin), hinst))
|| (!hpin_is_output
&& network_->isInside(network_->instance(cpin), hinst))))
pins.push_back(cpin);
}
delete cpin_iter;
2019-10-25 08:51:59 -07:00
}
else
2026-01-03 16:59:35 -08:00
pins.push_back(pin);
2019-10-25 08:51:59 -07:00
}
}
}
2018-09-28 08:54:21 -07:00
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDataChecks() const
{
2026-01-03 16:59:35 -08:00
std::vector<DataCheck*> checks;
2024-06-27 13:57:58 -07:00
for (const auto [pin, checks1] : sdc_->data_checks_to_map_) {
2023-01-19 11:23:45 -07:00
for (DataCheck *check : *checks1)
2018-09-28 08:54:21 -07:00
checks.push_back(check);
}
sort(checks, DataCheckLess(sdc_network_));
2023-01-19 11:23:45 -07:00
for (DataCheck *check : checks)
2018-09-28 08:54:21 -07:00
writeDataCheck(check);
}
void
WriteSdc::writeDataCheck(DataCheck *check) const
{
2019-07-18 06:19:00 -07:00
for (auto setup_hold : SetupHold::range()) {
2018-09-28 08:54:21 -07:00
float margin;
bool one_value;
check->marginIsOneValue(setup_hold, margin, one_value);
if (one_value)
2019-11-11 15:30:19 -07:00
writeDataCheck(check, RiseFallBoth::riseFall(),
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), setup_hold, margin);
2018-09-28 08:54:21 -07:00
else {
2019-11-11 15:30:19 -07:00
for (auto from_rf : RiseFall::range()) {
2026-01-03 16:59:35 -08:00
for (auto to_rf : RiseFall::range()) {
float margin;
bool margin_exists;
check->margin(from_rf, to_rf, setup_hold, margin, margin_exists);
if (margin_exists) {
writeDataCheck(check, from_rf->asRiseFallBoth(),
to_rf->asRiseFallBoth(), setup_hold, margin);
}
}
2018-09-28 08:54:21 -07:00
}
}
}
}
void
WriteSdc::writeDataCheck(DataCheck *check,
2026-01-03 16:59:35 -08:00
const RiseFallBoth *from_rf,
const RiseFallBoth *to_rf,
const SetupHold *setup_hold,
float margin) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view from_key = "-from";
2019-11-11 15:30:19 -07:00
if (from_rf == RiseFallBoth::rise())
2018-09-28 08:54:21 -07:00
from_key = "-rise_from";
2019-11-11 15:30:19 -07:00
else if (from_rf == RiseFallBoth::fall())
2018-09-28 08:54:21 -07:00
from_key = "-fall_from";
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_data_check {} ", from_key);
2019-10-25 08:51:59 -07:00
writeGetPin(check->from(), true);
2026-03-28 19:13:35 -07:00
std::string_view to_key = "-to";
2019-11-11 15:30:19 -07:00
if (to_rf == RiseFallBoth::rise())
2018-09-28 08:54:21 -07:00
to_key = "-rise_to";
2019-11-11 15:30:19 -07:00
else if (to_rf == RiseFallBoth::fall())
2018-09-28 08:54:21 -07:00
to_key = "-fall_to";
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {} ", to_key);
2019-10-25 08:51:59 -07:00
writeGetPin(check->to(), false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ",
setupHoldFlag(setup_hold));
2018-09-28 08:54:21 -07:00
writeTime(margin);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeEnvironment() const
{
writeCommentSection("Environment");
writeOperatingConditions();
writeWireload();
2020-07-05 16:37:50 -07:00
writePortLoads();
writeNetLoads();
2018-09-28 08:54:21 -07:00
writeDriveResistances();
writeDrivingCells();
writeInputTransitions();
writeNetResistances();
writeConstants();
writeCaseAnalysis();
writeDeratings();
2023-09-08 17:51:21 -07:00
writeVoltages();
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeOperatingConditions() const
{
OperatingConditions *cond = sdc_->operatingConditions(MinMax::max());
if (cond)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_operating_conditions {}\n", cond->name());
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeWireload() const
{
WireloadMode wireload_mode = sdc_->wireloadMode();
2019-03-12 17:25:53 -07:00
if (wireload_mode != WireloadMode::unknown)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_wire_load_mode \"{}\"\n",
wireloadModeString(wireload_mode));
2018-09-28 08:54:21 -07:00
}
void
2020-07-05 16:37:50 -07:00
WriteSdc::writeNetLoads() const
{
2026-01-03 16:59:35 -08:00
for (const auto [net, caps] : sdc_->net_wire_cap_map_) {
2023-01-19 11:23:45 -07:00
float min_cap, max_cap;
bool min_exists, max_exists;
caps.value(MinMax::min(), min_cap, min_exists);
caps.value(MinMax::max(), max_cap, max_exists);
if (min_exists && max_exists
&& min_cap == max_cap)
writeNetLoad(net, MinMaxAll::all(), min_cap);
else {
if (min_exists)
writeNetLoad(net, MinMaxAll::min(), min_cap);
if (max_exists)
writeNetLoad(net, MinMaxAll::max(), max_cap);
2020-07-05 16:37:50 -07:00
}
}
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeNetLoad(const Net *net,
2026-01-03 16:59:35 -08:00
const MinMaxAll *min_max,
float cap) const
2020-07-05 16:37:50 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_load ");
sta::print(stream_, "{} ", minMaxFlag(min_max));
2020-07-05 16:37:50 -07:00
writeCapacitance(cap);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2020-07-05 16:37:50 -07:00
writeGetNet(net);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2020-07-05 16:37:50 -07:00
}
void
WriteSdc::writePortLoads() const
2018-09-28 08:54:21 -07:00
{
CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
writePortLoads(port);
}
delete port_iter;
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writePortLoads(const Port *port) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
const PortExtCap *ext_cap = sdc_->portExtCap(port);
2018-09-28 08:54:21 -07:00
if (ext_cap) {
WriteGetPort write_port(port, this);
writeRiseFallMinMaxCapCmd("set_load -pin_load",
2026-01-03 16:59:35 -08:00
ext_cap->pinCap(),
write_port);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxCapCmd("set_load -wire_load",
2026-01-03 16:59:35 -08:00
ext_cap->wireCap(),
write_port);
2018-09-28 08:54:21 -07:00
writeMinMaxIntValuesCmd("set_port_fanout_number",
2026-01-03 16:59:35 -08:00
ext_cap->fanout(), write_port);
2018-09-28 08:54:21 -07:00
}
}
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) {
2021-11-22 07:37:59 -08:00
for (auto rf : RiseFall::range()) {
2026-01-03 16:59:35 -08:00
if (drive->driveResistanceMinMaxEqual(rf)) {
float res;
bool exists;
drive->driveResistance(rf, MinMax::max(), res, exists);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_drive {} ",
transRiseFallFlag(rf));
2026-01-03 16:59:35 -08:00
writeResistance(res);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2026-01-03 16:59:35 -08:00
}
else {
for (auto min_max : MinMax::range()) {
float res;
bool exists;
drive->driveResistance(rf, min_max, res, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_drive {} {} ",
transRiseFallFlag(rf),
minMaxFlag(min_max));
2026-01-03 16:59:35 -08:00
writeResistance(res);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2026-01-03 16:59:35 -08:00
}
}
}
2018-09-28 08:54:21 -07:00
}
}
}
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) {
2019-11-11 15:30:19 -07:00
InputDriveCell *drive_rise_min = drive->driveCell(RiseFall::rise(),
2026-01-03 16:59:35 -08:00
MinMax::min());
2019-11-11 15:30:19 -07:00
InputDriveCell *drive_rise_max = drive->driveCell(RiseFall::rise(),
2026-01-03 16:59:35 -08:00
MinMax::max());
2019-11-11 15:30:19 -07:00
InputDriveCell *drive_fall_min = drive->driveCell(RiseFall::fall(),
2026-01-03 16:59:35 -08:00
MinMax::min());
2019-11-11 15:30:19 -07:00
InputDriveCell *drive_fall_max = drive->driveCell(RiseFall::fall(),
2026-01-03 16:59:35 -08:00
MinMax::max());
2018-09-28 08:54:21 -07:00
if (drive_rise_min
2026-01-03 16:59:35 -08:00
&& 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, nullptr, nullptr);
2018-09-28 08:54:21 -07:00
else {
2026-01-03 16:59:35 -08:00
if (drive_rise_min
&& drive_rise_max
&& drive_rise_min->equal(drive_rise_max))
writeDrivingCell(port, drive_rise_min, RiseFall::rise(), nullptr);
else {
if (drive_rise_min)
writeDrivingCell(port, drive_rise_min, RiseFall::rise(),
MinMax::min());
if (drive_rise_max)
writeDrivingCell(port, drive_rise_max, RiseFall::rise(),
MinMax::max());
}
if (drive_fall_min
&& drive_fall_max
&& drive_fall_min->equal(drive_fall_max))
writeDrivingCell(port, drive_fall_min, RiseFall::fall(), nullptr);
else {
if (drive_fall_min)
writeDrivingCell(port, drive_fall_min, RiseFall::fall(),
MinMax::min());
if (drive_fall_max)
writeDrivingCell(port, drive_fall_max, RiseFall::fall(),
MinMax::max());
}
2018-09-28 08:54:21 -07:00
}
}
}
delete port_iter;
}
void
WriteSdc::writeDrivingCell(Port *port,
2026-01-03 16:59:35 -08:00
InputDriveCell *drive_cell,
const RiseFall *rf,
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
const LibertyCell *cell = drive_cell->cell();
const LibertyPort *from_port = drive_cell->fromPort();
const LibertyPort *to_port = drive_cell->toPort();
2026-04-15 09:38:10 -07:00
const DriveCellSlews &from_slews = drive_cell->fromSlews();
2023-01-19 11:23:45 -07:00
const LibertyLibrary *lib = drive_cell->library();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_driving_cell");
2019-11-11 15:30:19 -07:00
if (rf)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {}", transRiseFallFlag(rf));
2018-09-28 08:54:21 -07:00
if (min_max)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " {}", minMaxFlag(min_max));
2019-02-16 12:07:59 -08:00
// Only write -library if it was specified in the sdc.
if (lib)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -library {}", lib->name());
sta::print(stream_, " -lib_cell {}", cell->name());
2018-09-28 08:54:21 -07:00
if (from_port)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -from_pin {{{}}}",
from_port->name());
sta::print(stream_,
" -pin {{{}}} -input_transition_rise ",
to_port->name());
2019-11-11 15:30:19 -07:00
writeTime(from_slews[RiseFall::riseIndex()]);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -input_transition_fall ");
2019-11-11 15:30:19 -07:00
writeTime(from_slews[RiseFall::fallIndex()]);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
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) {
2025-02-01 14:53:28 -08:00
const RiseFallMinMax *slews = drive->slews();
2018-09-28 08:54:21 -07:00
WriteGetPort write_port(port, this);
writeRiseFallMinMaxTimeCmd("set_input_transition", slews, write_port);
}
}
delete port_iter;
}
void
WriteSdc::writeNetResistances() const
{
NetSeq nets;
2024-06-27 13:57:58 -07:00
for (const auto [net, res] : sdc_->netResistances())
2018-09-28 08:54:21 -07:00
nets.push_back(net);
sort(nets, NetPathNameLess(sdc_network_));
2023-01-19 11:23:45 -07:00
for (const Net *net : nets) {
2018-09-28 08:54:21 -07:00
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
2026-01-03 16:59:35 -08:00
&& min_res == max_res)
2018-09-28 08:54:21 -07:00
writeNetResistance(net, MinMaxAll::all(), min_res);
else {
if (min_exists)
2026-01-03 16:59:35 -08:00
writeNetResistance(net, MinMaxAll::min(), min_res);
2018-09-28 08:54:21 -07:00
if (max_exists)
2026-01-03 16:59:35 -08:00
writeNetResistance(net, MinMaxAll::max(), max_res);
2018-09-28 08:54:21 -07:00
}
}
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeNetResistance(const Net *net,
2026-01-03 16:59:35 -08:00
const MinMaxAll *min_max,
float res) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_resistance ");
2018-09-28 08:54:21 -07:00
writeResistance(res);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", minMaxFlag(min_max));
2018-09-28 08:54:21 -07:00
writeGetNet(net);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeConstants() const
{
PinSeq pins;
sortedLogicValuePins(sdc_->logicValues(), pins);
2023-01-19 11:23:45 -07:00
for (const Pin *pin : pins)
2018-09-28 08:54:21 -07:00
writeConstant(pin);
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeConstant(const Pin *pin) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view cmd = setConstantCmd(pin);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2019-10-25 08:51:59 -07:00
writeGetPin(pin, false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2023-01-19 11:23:45 -07:00
WriteSdc::setConstantCmd(const Pin *pin) const
2018-09-28 08:54:21 -07:00
{
LogicValue value;
bool exists;
sdc_->logicValue(pin, value, exists);
switch (value) {
2019-03-12 17:25:53 -07:00
case LogicValue::zero:
2021-08-16 12:17:48 -07:00
return "set_logic_zero";
2019-03-12 17:25:53 -07:00
case LogicValue::one:
2018-09-28 08:54:21 -07:00
return "set_logic_one";
2019-03-12 17:25:53 -07:00
case LogicValue::unknown:
2018-09-28 08:54:21 -07:00
return "set_logic_dc";
2019-03-12 17:25:53 -07:00
case LogicValue::rise:
case LogicValue::fall:
2018-09-28 08:54:21 -07:00
default:
2024-01-07 19:23:53 -07:00
report_->critical(1621, "illegal set_logic value");
2026-03-28 19:13:35 -07:00
return {};
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeCaseAnalysis() const
{
PinSeq pins;
sortedLogicValuePins(sdc_->caseLogicValues(), pins);
2023-01-19 11:23:45 -07:00
for (const Pin *pin : pins)
2018-09-28 08:54:21 -07:00
writeCaseAnalysis(pin);
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeCaseAnalysis(const Pin *pin) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view value_str = caseAnalysisValueStr(pin);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_case_analysis {} ", value_str);
2019-10-25 08:51:59 -07:00
writeGetPin(pin, false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2023-01-19 11:23:45 -07:00
WriteSdc::caseAnalysisValueStr(const Pin *pin) const
2018-09-28 08:54:21 -07:00
{
LogicValue value;
bool exists;
sdc_->caseLogicValue(pin, value, exists);
switch (value) {
2019-03-12 17:25:53 -07:00
case LogicValue::zero:
2018-09-28 08:54:21 -07:00
return "0";
2019-03-12 17:25:53 -07:00
case LogicValue::one:
2018-09-28 08:54:21 -07:00
return "1";
2019-03-12 17:25:53 -07:00
case LogicValue::rise:
2018-09-28 08:54:21 -07:00
return "rising";
2019-03-12 17:25:53 -07:00
case LogicValue::fall:
2018-09-28 08:54:21 -07:00
return "falling";
2019-03-12 17:25:53 -07:00
case LogicValue::unknown:
2018-09-28 08:54:21 -07:00
default:
2024-01-07 19:23:53 -07:00
report_->critical(1622, "invalid set_case_analysis value");
2026-03-28 19:13:35 -07:00
return {};
2018-09-28 08:54:21 -07:00
}
}
void
2026-01-03 16:59:35 -08:00
WriteSdc::sortedLogicValuePins(const LogicValueMap &value_map,
PinSeq &pins) const
2018-09-28 08:54:21 -07:00
{
2024-06-27 13:57:58 -07:00
for (const auto [pin, value] : value_map)
2023-01-19 11:23:45 -07:00
pins.push_back(pin);
2018-09-28 08:54:21 -07:00
// Sort pins.
sort(pins, PinPathNameLess(sdc_network_));
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeDeratings() const
{
DeratingFactorsGlobal *factors = sdc_->derating_factors_;
if (factors)
writeDerating(factors);
2024-06-27 13:57:58 -07:00
for (const auto [net, factors] : sdc_->net_derating_factors_) {
2018-09-28 08:54:21 -07:00
WriteGetNet write_net(net, this);
2019-07-18 06:19:00 -07:00
for (auto early_late : EarlyLate::range()) {
2019-03-12 17:25:53 -07:00
writeDerating(factors, TimingDerateType::net_delay, early_late,
2026-01-03 16:59:35 -08:00
&write_net);
2018-09-28 08:54:21 -07:00
}
}
2024-06-27 13:57:58 -07:00
for (const auto [inst, factors] : sdc_->inst_derating_factors_) {
2018-09-28 08:54:21 -07:00
WriteGetInstance write_inst(inst, this);
writeDerating(factors, &write_inst);
}
2024-06-27 13:57:58 -07:00
for (const auto [cell, factors] : sdc_->cell_derating_factors_) {
2018-09-28 08:54:21 -07:00
WriteGetLibCell write_cell(cell, this);
writeDerating(factors, &write_cell);
}
}
void
WriteSdc::writeDerating(DeratingFactorsGlobal *factors) const
{
2019-07-18 06:19:00 -07:00
for (auto early_late : EarlyLate::range()) {
2018-09-28 08:54:21 -07:00
bool delay_is_one_value, check_is_one_value, net_is_one_value;
float delay_value, check_value, net_value;
2019-03-12 17:25:53 -07:00
factors->factors(TimingDerateType::cell_delay)->isOneValue(early_late,
2026-01-03 16:59:35 -08:00
delay_is_one_value,
delay_value);
2019-03-12 17:25:53 -07:00
factors->factors(TimingDerateType::net_delay)->isOneValue(early_late,
2026-01-03 16:59:35 -08:00
net_is_one_value,
net_value);
2018-09-28 08:54:21 -07:00
DeratingFactors *cell_check_factors =
2019-03-12 17:25:53 -07:00
factors->factors(TimingDerateType::cell_check);
2018-09-28 08:54:21 -07:00
cell_check_factors->isOneValue(early_late, check_is_one_value, check_value);
if (delay_is_one_value
2026-01-03 16:59:35 -08:00
&& net_is_one_value
&& delay_value == net_value
&& (!cell_check_factors->hasValue()
|| (check_is_one_value && check_value == 1.0))) {
2018-09-28 08:54:21 -07:00
if (delay_value != 1.0) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_timing_derate {} ", earlyLateFlag(early_late));
2026-01-03 16:59:35 -08:00
writeFloat(delay_value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
else {
2026-04-15 09:38:10 -07:00
for (size_t type_index = 0;
2026-01-03 16:59:35 -08:00
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, nullptr);
2018-09-28 08:54:21 -07:00
}
}
}
}
void
WriteSdc::writeDerating(DeratingFactorsCell *factors,
2026-01-03 16:59:35 -08:00
WriteSdcObject *write_obj) const
2018-09-28 08:54:21 -07:00
{
2019-07-18 06:19:00 -07:00
for (auto early_late : EarlyLate::range()) {
2022-01-13 16:29:38 -07:00
DeratingFactors *delay_factors=factors->factors(TimingDerateCellType::cell_delay);
2019-03-12 17:25:53 -07:00
writeDerating(delay_factors, TimingDerateType::cell_delay, early_late, write_obj);
2022-01-13 16:29:38 -07:00
DeratingFactors *check_factors=factors->factors(TimingDerateCellType::cell_check);
2019-03-12 17:25:53 -07:00
writeDerating(check_factors, TimingDerateType::cell_check, early_late, write_obj);
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeDerating(DeratingFactors *factors,
2026-01-03 16:59:35 -08:00
TimingDerateType type,
const MinMax *early_late,
WriteSdcObject *write_obj) const
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view type_key = timingDerateTypeKeyword(type);
2018-09-28 08:54:21 -07:00
bool is_one_value;
float value;
factors->isOneValue(early_late, is_one_value, value);
if (is_one_value) {
if (value != 1.0) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_timing_derate {} {} ",
type_key,
earlyLateFlag(early_late));
2018-09-28 08:54:21 -07:00
writeFloat(value);
if (write_obj) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
write_obj->write();
2018-09-28 08:54:21 -07:00
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
else {
2026-04-15 09:38:10 -07:00
for (size_t clk_data_index = 0;
2026-01-03 16:59:35 -08:00
clk_data_index < path_clk_or_data_count;
clk_data_index++) {
2018-09-28 08:54:21 -07:00
PathClkOrData clk_data = static_cast<PathClkOrData>(clk_data_index);
2026-03-28 19:13:35 -07:00
static constexpr std::string_view clk_data_keys[] = {"-clock", "-data"};
std::string_view clk_data_key = clk_data_keys[clk_data_index];
2018-09-28 08:54:21 -07:00
factors->isOneValue(clk_data, early_late, is_one_value, value);
if (is_one_value) {
2026-01-03 16:59:35 -08:00
if (value != 1.0) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_timing_derate {} {} {} ",
type_key,
earlyLateFlag(early_late),
clk_data_key);
2026-01-03 16:59:35 -08:00
writeFloat(value);
if (write_obj) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
write_obj->write();
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2026-01-03 16:59:35 -08:00
}
2018-09-28 08:54:21 -07:00
}
else {
2026-01-03 16:59:35 -08:00
for (auto rf : RiseFall::range()) {
float factor;
bool exists;
factors->factor(clk_data, rf, early_late, factor, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_timing_derate {} {} {} {} ",
type_key,
clk_data_key,
transRiseFallFlag(rf),
earlyLateFlag(early_late));
2026-01-03 16:59:35 -08:00
writeFloat(factor);
if (write_obj) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
write_obj->write();
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2026-01-03 16:59:35 -08:00
}
}
2018-09-28 08:54:21 -07:00
}
}
}
}
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
timingDerateTypeKeyword(TimingDerateType type)
{
2026-03-28 19:13:35 -07:00
static constexpr std::string_view type_keys[] = {
"-cell_delay", "-cell_check", "-net_delay"};
2018-09-28 08:54:21 -07:00
return type_keys[static_cast<int>(type)];
}
////////////////////////////////////////////////////////////////
2023-09-08 17:51:21 -07:00
void
WriteSdc::writeVoltages() const
{
float voltage_max, voltage_min;
bool exists_max, exists_min;
sdc_->voltage(MinMax::max(), voltage_max, exists_max);
if (exists_max) {
sdc_->voltage(MinMax::min(), voltage_min, exists_min);
if (exists_min)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_voltage -min {:.3f} {:.3f}\n",
voltage_min,
voltage_max);
2023-09-08 17:51:21 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_voltage {:.3f}\n", voltage_max);
2023-09-08 17:51:21 -07:00
}
2024-06-27 13:57:58 -07:00
for (const auto& [net, volts] : sdc_->net_voltage_map_) {
volts.value(MinMax::max(), voltage_max, exists_max);
2023-09-08 17:51:21 -07:00
if (exists_max) {
2024-06-27 13:57:58 -07:00
volts.value(MinMax::min(), voltage_min, exists_min);
2023-09-08 17:51:21 -07:00
if (exists_min)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_voltage -object_list {} -min {:.3f} {:.3f}\n",
sdc_network_->pathName(net),
voltage_min,
voltage_max);
2023-09-08 17:51:21 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_voltage -object_list {} {:.3f}\n",
sdc_network_->pathName(net),
voltage_max);
2023-09-08 17:51:21 -07:00
}
}
}
////////////////////////////////////////////////////////////////
2018-09-28 08:54:21 -07:00
void
WriteSdc::writeDesignRules() const
{
writeCommentSection("Design Rules");
writeMinPulseWidths();
writeLatchBorowLimits();
writeSlewLimits();
writeCapLimits();
writeFanoutLimits();
writeMaxArea();
}
void
WriteSdc::writeMinPulseWidths() const
{
2024-06-27 13:57:58 -07:00
for (const auto [pin, min_widths] : sdc_->pin_min_pulse_width_map_) {
2019-10-25 08:51:59 -07:00
WriteGetPin write_obj(pin, false, this);
2018-09-28 08:54:21 -07:00
writeMinPulseWidths(min_widths, write_obj);
}
2023-01-19 11:23:45 -07:00
2024-06-27 13:57:58 -07:00
for (const auto [inst, min_widths] : sdc_->inst_min_pulse_width_map_) {
2018-09-28 08:54:21 -07:00
WriteGetInstance write_obj(inst, this);
writeMinPulseWidths(min_widths, write_obj);
}
2023-01-19 11:23:45 -07:00
2024-06-27 13:57:58 -07:00
for (const auto [clk, min_widths] : sdc_->clk_min_pulse_width_map_) {
2018-09-28 08:54:21 -07:00
WriteGetClock write_obj(clk, this);
writeMinPulseWidths(min_widths, write_obj);
}
}
void
WriteSdc::writeMinPulseWidths(RiseFallValues *min_widths,
2026-01-03 16:59:35 -08:00
WriteSdcObject &write_obj) const
2018-09-28 08:54:21 -07:00
{
bool hi_exists, low_exists;
float hi, low;
2019-11-11 15:30:19 -07:00
min_widths->value(RiseFall::rise(), hi, hi_exists);
min_widths->value(RiseFall::fall(), low, low_exists);
2018-09-28 08:54:21 -07:00
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
2026-03-28 19:13:35 -07:00
WriteSdc::writeMinPulseWidth(std::string_view hi_low,
2026-01-03 16:59:35 -08:00
float value,
WriteSdcObject &write_obj) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_min_pulse_width {}", hi_low);
2018-09-28 08:54:21 -07:00
writeTime(value);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
write_obj.write();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeLatchBorowLimits() const
{
2024-06-27 13:57:58 -07:00
for (const auto [pin, limit] : sdc_->pin_latch_borrow_limit_map_) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_time_borrow ");
2018-09-28 08:54:21 -07:00
writeTime(limit);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
2024-06-27 13:57:58 -07:00
for (const auto [inst, limit] : sdc_->inst_latch_borrow_limit_map_) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_time_borrow ");
2018-09-28 08:54:21 -07:00
writeTime(limit);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetInstance(inst);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
2024-06-27 13:57:58 -07:00
for (const auto [clk, limit] : sdc_->clk_latch_borrow_limit_map_) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_time_borrow ");
2018-09-28 08:54:21 -07:00
writeTime(limit);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeSlewLimits() const
{
const MinMax *min_max = MinMax::max();
float slew;
bool exists;
sdc_->slewLimit(cell_, min_max, slew, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_transition ");
2018-09-28 08:54:21 -07:00
writeTime(slew);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " [current_design]\n");
2018-09-28 08:54:21 -07:00
}
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) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_transition ");
2018-09-28 08:54:21 -07:00
writeTime(slew);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
delete port_iter;
writeClkSlewLimits();
}
void
WriteSdc::writeClkSlewLimits() const
{
const MinMax *min_max = MinMax::max();
2026-01-03 16:59:35 -08:00
ClockSeq clks = sdc_->sortedClocks();
2023-01-19 11:23:45 -07:00
for (const Clock *clk : clks) {
2018-09-28 08:54:21 -07:00
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;
2019-11-11 15:30:19 -07:00
clk->slewLimit(RiseFall::rise(), PathClkOrData::clk, min_max,
2026-01-03 16:59:35 -08:00
rise_clk_limit, rise_clk_exists);
2019-11-11 15:30:19 -07:00
clk->slewLimit(RiseFall::fall(), PathClkOrData::clk, min_max,
2026-01-03 16:59:35 -08:00
fall_clk_limit, fall_clk_exists);
2019-11-11 15:30:19 -07:00
clk->slewLimit(RiseFall::rise(), PathClkOrData::data, min_max,
2026-01-03 16:59:35 -08:00
rise_data_limit, rise_data_exists);
2019-11-11 15:30:19 -07:00
clk->slewLimit(RiseFall::fall(), PathClkOrData::data, min_max,
2026-01-03 16:59:35 -08:00
fall_data_limit, fall_data_exists);
2018-09-28 08:54:21 -07:00
if (rise_clk_exists && fall_clk_exists
2026-01-03 16:59:35 -08:00
&& rise_data_exists && fall_data_exists
&& fall_clk_limit == rise_clk_limit
&& rise_data_limit == rise_clk_limit
&& fall_data_limit == rise_clk_limit)
2018-09-28 08:54:21 -07:00
writeClkSlewLimit("", "", clk, rise_clk_limit);
else {
if (rise_clk_exists && fall_clk_exists
2026-01-03 16:59:35 -08:00
&& fall_clk_limit == rise_clk_limit)
writeClkSlewLimit("-clock_path ", "", clk, rise_clk_limit);
2018-09-28 08:54:21 -07:00
else {
2026-01-03 16:59:35 -08:00
if (rise_clk_exists)
writeClkSlewLimit("-clock_path ", "-rise ", clk, rise_clk_limit);
if (fall_clk_exists)
writeClkSlewLimit("-clock_path ", "-fall ", clk, fall_clk_limit);
2018-09-28 08:54:21 -07:00
}
if (rise_data_exists && fall_data_exists
2026-01-03 16:59:35 -08:00
&& fall_data_limit == rise_data_limit)
writeClkSlewLimit("-data_path ", "", clk, rise_data_limit);
2018-09-28 08:54:21 -07:00
else {
2026-01-03 16:59:35 -08:00
if (rise_data_exists)
writeClkSlewLimit("-data_path ", "-rise ", clk, rise_data_limit);
if (fall_data_exists) {
writeClkSlewLimit("-data_path ", "-fall ", clk, fall_data_limit);
}
2018-09-28 08:54:21 -07:00
}
}
}
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeClkSlewLimit(std::string_view clk_data,
std::string_view rise_fall,
2026-01-03 16:59:35 -08:00
const Clock *clk,
float limit) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_transition {}{}", clk_data, rise_fall);
2018-09-28 08:54:21 -07:00
writeTime(limit);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeCapLimits() const
{
writeCapLimits(MinMax::min(), "set_min_capacitance");
writeCapLimits(MinMax::max(), "set_max_capacitance");
}
void
WriteSdc::writeCapLimits(const MinMax *min_max,
2026-03-28 19:13:35 -07:00
std::string_view cmd) const
2018-09-28 08:54:21 -07:00
{
float cap;
bool exists;
sdc_->capacitanceLimit(cell_, min_max, cap, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2018-09-28 08:54:21 -07:00
writeCapacitance(cap);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " [current_design]\n");
2018-09-28 08:54:21 -07:00
}
2024-06-27 13:57:58 -07:00
for (const auto [port, limits] : sdc_->port_cap_limit_map_) {
2018-09-28 08:54:21 -07:00
float cap;
bool exists;
2024-06-27 13:57:58 -07:00
limits.value(min_max, cap, exists);
2018-09-28 08:54:21 -07:00
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2018-09-28 08:54:21 -07:00
writeCapacitance(cap);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
2024-06-27 13:57:58 -07:00
for (const auto [pin, limits] : sdc_->pin_cap_limit_map_) {
2018-09-28 08:54:21 -07:00
float cap;
bool exists;
2024-06-27 13:57:58 -07:00
limits.value(min_max, cap, exists);
2018-09-28 08:54:21 -07:00
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2018-09-28 08:54:21 -07:00
writeCapacitance(cap);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2019-10-25 08:51:59 -07:00
writeGetPin(pin, false);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
}
void
WriteSdc::writeMaxArea() const
{
float max_area = sdc_->maxArea();
if (max_area > 0.0) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set_max_area ");
2018-09-28 08:54:21 -07:00
writeFloat(max_area);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
void
WriteSdc::writeFanoutLimits() const
{
writeFanoutLimits(MinMax::min(), "set_min_fanout");
writeFanoutLimits(MinMax::max(), "set_max_fanout");
}
void
WriteSdc::writeFanoutLimits(const MinMax *min_max,
2026-03-28 19:13:35 -07:00
std::string_view cmd) const
2018-09-28 08:54:21 -07:00
{
float fanout;
bool exists;
sdc_->fanoutLimit(cell_, min_max, fanout, exists);
if (exists) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2018-09-28 08:54:21 -07:00
writeFloat(fanout);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " [current_design]\n");
2018-09-28 08:54:21 -07:00
}
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) {
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{} ", cmd);
2026-01-03 16:59:35 -08:00
writeFloat(fanout);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2026-01-03 16:59:35 -08:00
writeGetPort(port);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
}
delete port_iter;
}
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeVariables() const
{
2025-04-09 16:35:15 -07:00
if (variables_->propagateAllClocks()) {
2019-10-25 08:51:59 -07:00
if (native_)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set sta_propagate_all_clocks 1\n");
2019-10-25 08:51:59 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set timing_all_clocks_propagated true\n");
2018-09-28 08:54:21 -07:00
}
2025-04-09 16:35:15 -07:00
if (variables_->presetClrArcsEnabled()) {
2019-10-25 08:51:59 -07:00
if (native_)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set sta_preset_clear_arcs_enabled 1\n");
2019-10-25 08:51:59 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "set timing_enable_preset_clear_arcs true\n");
2018-09-28 08:54:21 -07:00
}
}
////////////////////////////////////////////////////////////////
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeGetTimingArcsOfOjbects(const LibertyCell *cell) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[{} -of_objects ", getTimingArcsCmd());
2018-09-28 08:54:21 -07:00
writeGetLibCell(cell);
2026-03-15 14:35:24 -07:00
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetTimingArcs(Edge *edge,
2026-03-28 19:13:35 -07:00
std::string_view filter) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[{} -from ", getTimingArcsCmd());
2018-09-28 08:54:21 -07:00
Vertex *from_vertex = edge->from(graph_);
2019-10-25 08:51:59 -07:00
writeGetPin(from_vertex->pin(), true);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -to ");
2018-09-28 08:54:21 -07:00
Vertex *to_vertex = edge->to(graph_);
2019-10-25 08:51:59 -07:00
writeGetPin(to_vertex->pin(), false);
2026-03-28 19:13:35 -07:00
if (!filter.empty())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -filter {{{}}}", filter);
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string_view
2018-09-28 08:54:21 -07:00
WriteSdc::getTimingArcsCmd() const
{
2019-10-25 08:51:59 -07:00
return native_ ? "get_timing_edges" : "get_timing_arcs";
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
WriteSdc::writeGetLibCell(const LibertyCell *cell) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_lib_cells {{{}/{}}}]",
2026-01-03 16:59:35 -08:00
cell->libertyLibrary()->name(),
cell->name());
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetLibPin(const LibertyPort *port) const
{
LibertyCell *cell = port->libertyCell();
LibertyLibrary *lib = cell->libertyLibrary();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_lib_pins {{{}/{}/{}}}]",
lib->name(),
cell->name(),
port->name());
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetClocks(ClockSet *clks) const
{
bool first = true;
bool multiple = clks->size() > 1;
if (multiple)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[list ");
2018-09-28 08:54:21 -07:00
writeGetClocks(clks, multiple, first);
if (multiple)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetClocks(ClockSet *clks,
2026-01-03 16:59:35 -08:00
bool multiple,
bool &first) const
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
ClockSeq clks1 = sortByName(clks);
for (const Clock *clk : clks1) {
2018-09-28 08:54:21 -07:00
if (multiple && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
first = false;
}
}
void
WriteSdc::writeGetClock(const Clock *clk) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_clocks {{{}}}]",
clk->name());
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetPort(const Port *port) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_ports {{{}}}]", sdc_network_->name(port));
2018-09-28 08:54:21 -07:00
}
void
2023-01-19 11:23:45 -07:00
WriteSdc::writeGetPins(const PinSet *pins,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr) const
2018-09-28 08:54:21 -07:00
{
2020-01-05 11:35:51 -08:00
if (map_hpins_) {
2023-01-19 11:23:45 -07:00
PinSet leaf_pins(network_);;
for (const Pin *pin : *pins) {
2020-01-05 11:35:51 -08:00
if (network_->isHierarchical(pin)) {
2026-01-03 16:59:35 -08:00
if (map_hpin_to_drvr)
findLeafDriverPins(const_cast<Pin*>(pin), network_, &leaf_pins);
else
findLeafLoadPins(const_cast<Pin*>(pin), network_, &leaf_pins);
2020-01-05 11:35:51 -08:00
}
else
2026-01-03 16:59:35 -08:00
leaf_pins.insert(pin);
2020-01-05 11:35:51 -08:00
}
2023-01-19 11:23:45 -07:00
PinSeq pins1 = sortByPathName(&leaf_pins, sdc_network_);
writeGetPins1(&pins1);
}
else {
PinSeq pins1 = sortByPathName(pins, sdc_network_);
writeGetPins1(&pins1);
2020-01-05 11:35:51 -08:00
}
2018-09-28 08:54:21 -07:00
}
void
2020-01-05 11:35:51 -08:00
WriteSdc::writeGetPins1(PinSeq *pins) const
2018-09-28 08:54:21 -07:00
{
bool multiple = pins->size() > 1;
if (multiple)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[list ");
2018-09-28 08:54:21 -07:00
bool first = true;
2023-01-19 11:23:45 -07:00
for (const Pin *pin : *pins) {
2018-09-28 08:54:21 -07:00
if (multiple && !first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\\\n ");
2020-01-05 11:35:51 -08:00
writeGetPin(pin);
2018-09-28 08:54:21 -07:00
first = false;
}
if (multiple)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "]");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetPin(const Pin *pin) const
{
if (sdc_network_->instance(pin) == instance_)
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_ports {{{}}}]", sdc_network_->portName(pin));
2018-09-28 08:54:21 -07:00
else
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_pins {{{}}}]", pathName(pin));
2018-09-28 08:54:21 -07:00
}
2019-10-25 08:51:59 -07:00
void
WriteSdc::writeGetPin(const Pin *pin,
2026-01-03 16:59:35 -08:00
bool map_hpin_to_drvr) const
2019-10-25 08:51:59 -07:00
{
2020-01-05 11:35:51 -08:00
if (map_hpins_ && network_->isHierarchical(pin)) {
2023-01-19 11:23:45 -07:00
PinSet pins(network_);
2020-01-05 11:35:51 -08:00
pins.insert(const_cast<Pin*>(pin));
writeGetPins(&pins, map_hpin_to_drvr);
2019-10-25 08:51:59 -07:00
}
2020-01-05 11:35:51 -08:00
else
writeGetPin(pin);
2019-10-25 08:51:59 -07:00
}
2018-09-28 08:54:21 -07:00
void
WriteSdc::writeGetNet(const Net *net) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_nets {{{}}}]", pathName(net));
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeGetInstance(const Instance *inst) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "[get_cells {{{}}}]", pathName(inst));
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string
2018-09-28 08:54:21 -07:00
WriteSdc::pathName(const Pin *pin) const
{
2026-03-28 19:13:35 -07:00
std::string pin_path = sdc_network_->pathName(pin);
2018-09-28 08:54:21 -07:00
if (top_instance_)
return pin_path;
else
2026-03-28 19:13:35 -07:00
return pin_path.substr(instance_name_length_ + 1);
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string
2018-09-28 08:54:21 -07:00
WriteSdc::pathName(const Net *net) const
{
2026-03-28 19:13:35 -07:00
std::string net_path = sdc_network_->pathName(net);
2018-09-28 08:54:21 -07:00
if (top_instance_)
return net_path;
else
2026-03-28 19:13:35 -07:00
return net_path.substr(instance_name_length_ + 1);
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string
2018-09-28 08:54:21 -07:00
WriteSdc::pathName(const Instance *inst) const
{
2026-03-28 19:13:35 -07:00
std::string inst_path = sdc_network_->pathName(inst);
2018-09-28 08:54:21 -07:00
if (top_instance_)
return inst_path;
else
2026-03-28 19:13:35 -07:00
return inst_path.substr(instance_name_length_ + 1);
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeCommentSection(std::string_view line) const
2018-09-28 08:54:21 -07:00
{
writeCommentSeparator();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "# {}\n", line);
2018-09-28 08:54:21 -07:00
writeCommentSeparator();
}
void
WriteSdc::writeCommentSeparator() const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "###############################################################################\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeRiseFallMinMaxTimeCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
const RiseFallMinMax *values,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
writeRiseFallMinMaxCmd(sdc_cmd, values, units_->timeUnit()->scale(),
2026-01-03 16:59:35 -08:00
write_object);
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeRiseFallMinMaxCapCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
const RiseFallMinMax *values,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
writeRiseFallMinMaxCmd(sdc_cmd, values, units_->capacitanceUnit()->scale(),
2026-01-03 16:59:35 -08:00
write_object);
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeRiseFallMinMaxCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
const RiseFallMinMax *values,
float scale,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
float fall_min, fall_max, rise_min, rise_max;
bool fall_min_exists, fall_max_exists, rise_min_exists, rise_max_exists;
2019-11-11 15:30:19 -07:00
values->value(RiseFall::fall(), MinMax::min(),
2026-01-03 16:59:35 -08:00
fall_min, fall_min_exists);
2019-11-11 15:30:19 -07:00
values->value(RiseFall::fall(), MinMax::max(),
2026-01-03 16:59:35 -08:00
fall_max, fall_max_exists);
2019-11-11 15:30:19 -07:00
values->value(RiseFall::rise(), MinMax::min(),
2026-01-03 16:59:35 -08:00
rise_min, rise_min_exists);
2019-11-11 15:30:19 -07:00
values->value(RiseFall::rise(), MinMax::max(),
2026-01-03 16:59:35 -08:00
rise_max, rise_max_exists);
2018-09-28 08:54:21 -07:00
if (fall_min_exists && fall_max_exists
&& rise_min_exists && rise_max_exists) {
if (fall_min == rise_min
2026-01-03 16:59:35 -08:00
&& rise_max == rise_min
&& fall_max == rise_min) {
2018-09-28 08:54:21 -07:00
// rise/fall/min/max match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::all(),
write_object);
2018-09-28 08:54:21 -07:00
}
else if (rise_min == fall_min
2026-01-03 16:59:35 -08:00
&& rise_max == fall_max) {
2018-09-28 08:54:21 -07:00
// rise/fall match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::min(),
write_object);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxCmd(sdc_cmd, rise_max, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::riseFall(), MinMaxAll::max(),
write_object);
2018-09-28 08:54:21 -07:00
}
else if (rise_min == rise_max
2026-01-03 16:59:35 -08:00
&& fall_min == fall_max) {
2018-09-28 08:54:21 -07:00
// min/max match.
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::all(),
write_object);
2018-09-28 08:54:21 -07:00
writeRiseFallMinMaxCmd(sdc_cmd, fall_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::all(),
write_object);
2018-09-28 08:54:21 -07:00
}
}
else {
if (rise_min_exists)
writeRiseFallMinMaxCmd(sdc_cmd, rise_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::min(),
write_object);
2018-09-28 08:54:21 -07:00
if (rise_max_exists)
writeRiseFallMinMaxCmd(sdc_cmd, rise_max, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::rise(), MinMaxAll::max(),
write_object);
2018-09-28 08:54:21 -07:00
if (fall_min_exists)
writeRiseFallMinMaxCmd(sdc_cmd, fall_min, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::min(),
write_object);
2018-09-28 08:54:21 -07:00
if (fall_max_exists)
writeRiseFallMinMaxCmd(sdc_cmd, fall_max, scale,
2026-01-03 16:59:35 -08:00
RiseFallBoth::fall(), MinMaxAll::max(),
write_object);
2018-09-28 08:54:21 -07:00
}
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeRiseFallMinMaxCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
float value,
float scale,
const RiseFallBoth *rf,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}{}{} ",
sdc_cmd,
transRiseFallFlag(rf),
minMaxFlag(min_max));
2018-09-28 08:54:21 -07:00
writeFloat(value / scale);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
write_object.write();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeClockKey(const Clock *clk) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -clock ");
2018-09-28 08:54:21 -07:00
writeGetClock(clk);
}
////////////////////////////////////////////////////////////////
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeMinMaxFloatValuesCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
const MinMaxFloatValues *values,
float scale,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
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
2026-03-28 19:13:35 -07:00
WriteSdc::writeMinMaxFloatCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
float value,
float scale,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}{} ",
sdc_cmd,
minMaxFlag(min_max));
2018-09-28 08:54:21 -07:00
writeFloat(value / scale);
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
write_object.write();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
WriteSdc::writeMinMaxIntValuesCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
const MinMaxIntValues *values,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
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
2026-03-28 19:13:35 -07:00
WriteSdc::writeMinMaxIntCmd(std::string_view sdc_cmd,
2026-01-03 16:59:35 -08:00
int value,
const MinMaxAll *min_max,
WriteSdcObject &write_object) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}{} ",
sdc_cmd,
minMaxFlag(min_max));
sta::print(stream_, "{} ", value);
2018-09-28 08:54:21 -07:00
write_object.write();
2026-03-15 14:35:24 -07:00
sta::print(stream_, "\n");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
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
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", value, digits_));
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeTime(float time) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleTime(time), digits_));
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeCapacitance(float cap) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleCapacitance(cap), digits_));
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeResistance(float res) const
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleResistance(res), digits_));
2018-09-28 08:54:21 -07:00
}
void
2026-04-16 18:42:26 -07:00
WriteSdc::writeFloatSeq(const FloatSeq &floats,
2026-01-03 16:59:35 -08:00
float scale) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{{");
2018-09-28 08:54:21 -07:00
bool first = true;
2026-04-16 18:42:26 -07:00
for (float flt : floats) {
2018-09-28 08:54:21 -07:00
if (!first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
2018-09-28 08:54:21 -07:00
writeFloat(flt * scale);
first = false;
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "}}");
2018-09-28 08:54:21 -07:00
}
void
2026-04-16 18:42:26 -07:00
WriteSdc::writeIntSeq(const IntSeq &ints) const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
sta::print(stream_, "{{");
2018-09-28 08:54:21 -07:00
bool first = true;
2026-04-16 18:42:26 -07:00
for (int i : ints) {
2018-09-28 08:54:21 -07:00
if (!first)
2026-03-15 14:35:24 -07:00
sta::print(stream_, " ");
sta::print(stream_, "{}", i);
2018-09-28 08:54:21 -07:00
first = false;
}
2026-03-15 14:35:24 -07:00
sta::print(stream_, "}}");
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
2026-03-28 19:13:35 -07:00
static std::string_view
2019-11-11 15:30:19 -07:00
transRiseFallFlag(const RiseFall *rf)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
return (rf == RiseFall::rise()) ? "-rise" : "-fall";
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
static std::string_view
2019-11-11 15:30:19 -07:00
transRiseFallFlag(const RiseFallBoth *rf)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
if (rf == RiseFallBoth::rise())
2018-09-28 08:54:21 -07:00
return " -rise";
2019-11-11 15:30:19 -07:00
else if (rf == RiseFallBoth::fall())
2018-09-28 08:54:21 -07:00
return " -fall";
2020-12-13 18:21:35 -07:00
else
2018-09-28 08:54:21 -07:00
return "";
}
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
minMaxFlag(const MinMaxAll *min_max)
{
2020-12-13 18:21:35 -07:00
if (min_max == MinMaxAll::min())
2018-09-28 08:54:21 -07:00
return " -min";
else if (min_max == MinMaxAll::max())
return " -max";
2020-12-13 18:21:35 -07:00
else
return "";
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
minMaxFlag(const MinMax *min_max)
{
2020-12-13 18:21:35 -07:00
return (min_max == MinMax::min()) ? " -min" : " -max";
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
earlyLateFlag(const MinMax *early_late)
{
2020-12-13 18:21:35 -07:00
return (early_late == MinMax::min()) ? "-early" : "-late";
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeSetupHoldFlag(const MinMaxAll *min_max) const
{
if (min_max == MinMaxAll::min())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -hold");
2018-09-28 08:54:21 -07:00
else if (min_max == MinMaxAll::max())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -setup");
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
static std::string_view
2018-09-28 08:54:21 -07:00
setupHoldFlag(const MinMax *min_max)
{
2020-12-13 18:21:35 -07:00
return (min_max == MinMax::min()) ? " -hold" : " -setup";
2018-09-28 08:54:21 -07:00
}
void
WriteSdc::writeCmdComment(SdcCmdComment *cmd) const
{
2026-04-15 09:38:10 -07:00
const std::string &comment = cmd->comment();
2026-03-28 19:13:35 -07:00
if (!comment.empty())
2026-03-15 14:35:24 -07:00
sta::print(stream_, " -comment {{{}}}", comment);
2018-09-28 08:54:21 -07:00
}
2026-04-13 14:58:16 -07:00
} // namespace sta