2018-12-26 20:03:31 +01:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2019-01-01 21:26:11 +01:00
|
|
|
// Copyright (c) 2019, Parallax Software, Inc.
|
2018-12-26 20:03:31 +01:00
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
#include "Machine.hh"
|
|
|
|
|
#include "StringUtil.hh"
|
|
|
|
|
#include "MinMax.hh"
|
|
|
|
|
#include "Transition.hh"
|
|
|
|
|
#include "PortDirection.hh"
|
|
|
|
|
#include "Units.hh"
|
|
|
|
|
#include "TimingArc.hh"
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "Graph.hh"
|
|
|
|
|
#include "Clock.hh"
|
|
|
|
|
#include "Corner.hh"
|
|
|
|
|
#include "PathEnd.hh"
|
|
|
|
|
#include "PathExpanded.hh"
|
|
|
|
|
#include "PathRef.hh"
|
2019-04-29 17:39:05 +02:00
|
|
|
#include "Power.hh"
|
2018-12-26 20:03:31 +01:00
|
|
|
#include "Sta.hh"
|
2019-01-17 00:37:31 +01:00
|
|
|
#include "Property.hh"
|
2018-12-26 20:03:31 +01:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
using std::string;
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
static PropertyValue
|
|
|
|
|
pinSlewProperty(const Pin *pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
static PropertyValue
|
|
|
|
|
pinSlackProperty(const Pin *pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
static PropertyValue
|
|
|
|
|
portSlewProperty(const Port *port,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
static PropertyValue
|
|
|
|
|
portSlackProperty(const Port *port,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
static PropertyValue
|
|
|
|
|
edgeDelayProperty(Edge *edge,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
static float
|
|
|
|
|
delayPropertyValue(Delay delay,
|
|
|
|
|
Sta *sta);
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-02-17 00:31:39 +01:00
|
|
|
class PropertyUnknown : public StaException
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
PropertyUnknown(const char *type,
|
|
|
|
|
const char *property);
|
|
|
|
|
virtual ~PropertyUnknown() THROW_DCL {}
|
|
|
|
|
virtual const char *what() const throw();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const char *type_;
|
|
|
|
|
const char *property_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PropertyUnknown::PropertyUnknown(const char *type,
|
|
|
|
|
const char *property) :
|
|
|
|
|
type_(type),
|
|
|
|
|
property_(property)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
PropertyUnknown::what() const throw()
|
|
|
|
|
{
|
2019-07-01 02:17:03 +02:00
|
|
|
return stringPrint("Error: %s objects do not have a %s property.",
|
2019-02-17 00:31:39 +01:00
|
|
|
type_, property_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue::PropertyValue() :
|
|
|
|
|
type_(type_none)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(const char *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_string),
|
|
|
|
|
string_(stringCopy(value))
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
PropertyValue::PropertyValue(std::string &value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_string),
|
|
|
|
|
string_(stringCopy(value.c_str()))
|
2019-01-17 00:37:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue::PropertyValue(float value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_float),
|
|
|
|
|
float_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 05:02:33 +02:00
|
|
|
PropertyValue::PropertyValue(bool value) :
|
|
|
|
|
type_(type_bool),
|
|
|
|
|
bool_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
PropertyValue::PropertyValue(LibertyLibrary *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_liberty_library),
|
|
|
|
|
liberty_library_(value)
|
2019-01-17 00:37:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(LibertyCell *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_liberty_cell),
|
|
|
|
|
liberty_cell_(value)
|
2019-01-17 00:37:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-02 16:07:34 +02:00
|
|
|
PropertyValue::PropertyValue(LibertyPort *value) :
|
|
|
|
|
type_(type_liberty_port),
|
|
|
|
|
liberty_port_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-17 00:31:39 +01:00
|
|
|
PropertyValue::PropertyValue(Library *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_library),
|
|
|
|
|
library_(value)
|
2019-02-17 00:31:39 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
PropertyValue::PropertyValue(Cell *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_cell),
|
|
|
|
|
cell_(value)
|
2019-01-17 00:37:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-02 16:07:34 +02:00
|
|
|
PropertyValue::PropertyValue(Port *value) :
|
|
|
|
|
type_(type_port),
|
|
|
|
|
port_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue::PropertyValue(Instance *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_instance),
|
|
|
|
|
inst_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(Pin *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_pin),
|
|
|
|
|
pin_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(PinSeq *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_pins),
|
|
|
|
|
pins_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(PinSet *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_pins),
|
|
|
|
|
pins_(new PinSeq)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
PinSet::Iterator pin_iter(value);
|
|
|
|
|
while (pin_iter.hasNext()) {
|
|
|
|
|
Pin *pin = pin_iter.next();
|
|
|
|
|
pins_->push_back( pin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(Net *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_net),
|
|
|
|
|
net_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(Clock *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_clk),
|
|
|
|
|
clk_(value)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(ClockSeq *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_clks),
|
|
|
|
|
clks_(new ClockSeq(*value))
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(ClockSet *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_clks),
|
|
|
|
|
clks_(new ClockSeq)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
ClockSet::Iterator clk_iter(value);
|
|
|
|
|
while (clk_iter.hasNext()) {
|
|
|
|
|
Clock *clk = clk_iter.next();
|
|
|
|
|
clks_->push_back(clk);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(PathRefSeq *value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(type_path_refs),
|
|
|
|
|
path_refs_(new PathRefSeq(*value))
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-29 17:39:05 +02:00
|
|
|
PropertyValue::PropertyValue(PwrActivity *value) :
|
|
|
|
|
type_(type_pwr_activity),
|
|
|
|
|
pwr_activity_(*value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue::PropertyValue(const PropertyValue &value) :
|
2019-03-13 01:25:53 +01:00
|
|
|
type_(value.type_)
|
|
|
|
|
{
|
|
|
|
|
switch (type_) {
|
|
|
|
|
case Type::type_none:
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_string:
|
|
|
|
|
string_ = stringCopy(value.string_);
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_float:
|
|
|
|
|
float_ = value.float_;
|
|
|
|
|
break;
|
2019-05-26 05:02:33 +02:00
|
|
|
case Type::type_bool:
|
|
|
|
|
bool_ = value.bool_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case Type::type_liberty_library:
|
|
|
|
|
liberty_library_ = value.liberty_library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_liberty_cell:
|
|
|
|
|
liberty_cell_ = value.liberty_cell_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_liberty_port:
|
|
|
|
|
liberty_port_ = value.liberty_port_;
|
2019-03-13 01:25:53 +01:00
|
|
|
break;
|
|
|
|
|
case Type::type_library:
|
|
|
|
|
library_ = value.library_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_cell:
|
|
|
|
|
cell_ = value.cell_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_port:
|
|
|
|
|
port_ = value.port_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case Type::type_instance:
|
|
|
|
|
inst_ = value.inst_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pin:
|
|
|
|
|
pin_ = value.pin_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pins:
|
|
|
|
|
pins_ = value.pins_ ? new PinSeq(*value.pins_) : nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_net:
|
|
|
|
|
net_ = value.net_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clk:
|
|
|
|
|
clk_ = value.clk_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clks:
|
|
|
|
|
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_path_refs:
|
|
|
|
|
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
|
|
|
|
break;
|
2019-04-29 17:39:05 +02:00
|
|
|
case Type::type_pwr_activity:
|
|
|
|
|
pwr_activity_ = value.pwr_activity_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::PropertyValue(PropertyValue &&value) :
|
|
|
|
|
type_(value.type_)
|
|
|
|
|
{
|
|
|
|
|
switch (type_) {
|
|
|
|
|
case Type::type_none:
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_string:
|
|
|
|
|
string_ = value.string_;
|
|
|
|
|
value.string_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_float:
|
|
|
|
|
float_ = value.float_;
|
|
|
|
|
break;
|
2019-05-26 05:02:33 +02:00
|
|
|
case Type::type_bool:
|
|
|
|
|
bool_ = value.bool_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_library:
|
|
|
|
|
library_ = value.library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_cell:
|
|
|
|
|
cell_ = value.cell_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_port:
|
|
|
|
|
port_ = value.port_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case Type::type_liberty_library:
|
|
|
|
|
liberty_library_ = value.liberty_library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_liberty_cell:
|
|
|
|
|
liberty_cell_ = value.liberty_cell_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_liberty_port:
|
|
|
|
|
liberty_port_ = value.liberty_port_;
|
2019-03-13 01:25:53 +01:00
|
|
|
break;
|
|
|
|
|
case Type::type_instance:
|
|
|
|
|
inst_ = value.inst_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pin:
|
|
|
|
|
pin_ = value.pin_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pins:
|
|
|
|
|
pins_ = value.pins_;
|
|
|
|
|
value.pins_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_net:
|
|
|
|
|
net_ = value.net_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clk:
|
|
|
|
|
clk_ = value.clk_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clks:
|
|
|
|
|
clks_ = value.clks_;
|
2019-04-29 17:39:05 +02:00
|
|
|
// Steal the value.
|
2019-03-13 01:25:53 +01:00
|
|
|
value.clks_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_path_refs:
|
|
|
|
|
path_refs_ = value.path_refs_;
|
2019-04-29 17:39:05 +02:00
|
|
|
// Steal the value.
|
2019-03-13 01:25:53 +01:00
|
|
|
value.clks_ = nullptr;
|
|
|
|
|
break;
|
2019-04-29 17:39:05 +02:00
|
|
|
case Type::type_pwr_activity:
|
|
|
|
|
pwr_activity_ = value.pwr_activity_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
}
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue::~PropertyValue()
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
switch (type_) {
|
|
|
|
|
case Type::type_string:
|
|
|
|
|
stringDelete(string_);
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clks:
|
|
|
|
|
delete clks_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pins:
|
|
|
|
|
delete pins_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_path_refs:
|
|
|
|
|
delete path_refs_;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-13 01:25:53 +01:00
|
|
|
PropertyValue &
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue::operator=(const PropertyValue &value)
|
|
|
|
|
{
|
|
|
|
|
type_ = value.type_;
|
2019-03-13 01:25:53 +01:00
|
|
|
switch (type_) {
|
|
|
|
|
case Type::type_none:
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_string:
|
|
|
|
|
string_ = stringCopy(value.string_);
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_float:
|
|
|
|
|
float_ = value.float_;
|
|
|
|
|
break;
|
2019-05-26 05:02:33 +02:00
|
|
|
case Type::type_bool:
|
|
|
|
|
bool_ = value.bool_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_library:
|
|
|
|
|
library_ = value.library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_cell:
|
|
|
|
|
cell_ = value.cell_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_port:
|
|
|
|
|
port_ = value.port_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case Type::type_liberty_library:
|
|
|
|
|
liberty_library_ = value.liberty_library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_liberty_cell:
|
|
|
|
|
liberty_cell_ = value.liberty_cell_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_liberty_port:
|
|
|
|
|
liberty_port_ = value.liberty_port_;
|
2019-03-13 01:25:53 +01:00
|
|
|
break;
|
|
|
|
|
case Type::type_instance:
|
|
|
|
|
inst_ = value.inst_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pin:
|
|
|
|
|
pin_ = value.pin_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pins:
|
|
|
|
|
pins_ = value.pins_ ? new PinSeq(*value.pins_) : nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_net:
|
|
|
|
|
net_ = value.net_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clk:
|
|
|
|
|
clk_ = value.clk_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clks:
|
|
|
|
|
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_path_refs:
|
|
|
|
|
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
|
|
|
|
break;
|
2019-04-29 17:39:05 +02:00
|
|
|
case Type::type_pwr_activity:
|
|
|
|
|
pwr_activity_ = value.pwr_activity_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue &
|
|
|
|
|
PropertyValue::operator=(PropertyValue &&value)
|
|
|
|
|
{
|
|
|
|
|
type_ = value.type_;
|
|
|
|
|
switch (type_) {
|
|
|
|
|
case Type::type_none:
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_string:
|
|
|
|
|
string_ = value.string_;
|
|
|
|
|
value.string_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_float:
|
|
|
|
|
float_ = value.float_;
|
|
|
|
|
break;
|
2019-05-26 05:02:33 +02:00
|
|
|
case Type::type_bool:
|
|
|
|
|
bool_ = value.bool_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_library:
|
|
|
|
|
library_ = value.library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_cell:
|
|
|
|
|
cell_ = value.cell_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_port:
|
|
|
|
|
port_ = value.port_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
case Type::type_liberty_library:
|
|
|
|
|
liberty_library_ = value.liberty_library_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_liberty_cell:
|
|
|
|
|
liberty_cell_ = value.liberty_cell_;
|
|
|
|
|
break;
|
2019-07-02 16:07:34 +02:00
|
|
|
case Type::type_liberty_port:
|
|
|
|
|
liberty_port_ = value.liberty_port_;
|
2019-03-13 01:25:53 +01:00
|
|
|
break;
|
|
|
|
|
case Type::type_instance:
|
|
|
|
|
inst_ = value.inst_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pin:
|
|
|
|
|
pin_ = value.pin_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_pins:
|
|
|
|
|
pins_ = value.pins_;
|
|
|
|
|
value.pins_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_net:
|
|
|
|
|
net_ = value.net_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clk:
|
|
|
|
|
clk_ = value.clk_;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_clks:
|
|
|
|
|
clks_ = value.clks_;
|
|
|
|
|
value.clks_ = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
case Type::type_path_refs:
|
|
|
|
|
path_refs_ = value.path_refs_;
|
|
|
|
|
value.clks_ = nullptr;
|
|
|
|
|
break;
|
2019-04-29 17:39:05 +02:00
|
|
|
case Type::type_pwr_activity:
|
|
|
|
|
pwr_activity_ = value.pwr_activity_;
|
|
|
|
|
break;
|
2019-03-13 01:25:53 +01:00
|
|
|
}
|
|
|
|
|
return *this;
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const Library *lib,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name"))
|
|
|
|
|
return PropertyValue(network->name(lib));
|
|
|
|
|
#if 0
|
|
|
|
|
else if (stringEqual(property, "filename"))
|
|
|
|
|
return PropertyValue(network->filename(lib));
|
|
|
|
|
#endif
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("library", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const LibertyLibrary *lib,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
2019-01-17 00:37:31 +01:00
|
|
|
Sta *)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name"))
|
|
|
|
|
return PropertyValue(lib->name());
|
|
|
|
|
else if (stringEqual(property, "filename"))
|
|
|
|
|
return PropertyValue(lib->filename());
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("liberty library", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
PropertyValue
|
|
|
|
|
getProperty(const LibertyCell *cell,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "base_name"))
|
|
|
|
|
return PropertyValue(cell->name());
|
|
|
|
|
else if (stringEqual(property, "full_name")) {
|
|
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
auto lib = cell->libertyLibrary();
|
|
|
|
|
const char *lib_name = lib->name();
|
|
|
|
|
const char *cell_name = cell->name();
|
|
|
|
|
string full_name;
|
|
|
|
|
stringPrint(full_name, "%s%c%s",
|
|
|
|
|
lib_name,
|
|
|
|
|
network->pathDivider(),
|
|
|
|
|
cell_name);
|
|
|
|
|
return PropertyValue(full_name);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "filename"))
|
|
|
|
|
return PropertyValue(cell->filename());
|
|
|
|
|
else if (stringEqual(property, "library"))
|
|
|
|
|
return PropertyValue(cell->libertyLibrary());
|
2019-05-26 05:02:33 +02:00
|
|
|
else if (stringEqual(property, "is_buffer"))
|
|
|
|
|
return PropertyValue(cell->isBuffer());
|
2019-06-16 19:20:51 +02:00
|
|
|
else if (stringEqual(property, "dont_use"))
|
|
|
|
|
return PropertyValue(cell->dontUse());
|
2019-01-17 00:37:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("liberty cell", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const Cell *cell,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "base_name"))
|
|
|
|
|
return PropertyValue(network->name(cell));
|
|
|
|
|
else if (stringEqual(property, "full_name")) {
|
|
|
|
|
auto lib = network->library(cell);
|
|
|
|
|
const char *lib_name = network->name(lib);
|
|
|
|
|
const char *cell_name = network->name(cell);
|
|
|
|
|
string full_name;
|
|
|
|
|
stringPrint(full_name, "%s%c%s",
|
|
|
|
|
lib_name,
|
|
|
|
|
network->pathDivider(),
|
|
|
|
|
cell_name);
|
|
|
|
|
return PropertyValue(full_name);
|
|
|
|
|
}
|
2019-02-17 00:31:39 +01:00
|
|
|
else if (stringEqual(property, "library"))
|
|
|
|
|
return PropertyValue(network->library(cell));
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "filename"))
|
|
|
|
|
return PropertyValue(network->filename(cell));
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("cell", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
|
|
|
|
getProperty(const Port *port,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name"))
|
2018-12-26 20:03:31 +01:00
|
|
|
return PropertyValue(network->name(port));
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "direction"))
|
|
|
|
|
return PropertyValue(network->direction(port)->name());
|
2019-07-02 16:07:34 +02:00
|
|
|
else if (stringEqual(property, "liberty_port"))
|
|
|
|
|
return PropertyValue(network->libertyPort(port));
|
|
|
|
|
|
2019-04-29 17:39:05 +02:00
|
|
|
else if (stringEqual(property, "activity")) {
|
|
|
|
|
const Instance *top_inst = network->topInstance();
|
|
|
|
|
const Pin *pin = network->findPin(top_inst, port);
|
2019-05-08 22:23:59 +02:00
|
|
|
PwrActivity activity = sta->power()->findClkedActivity(pin);
|
2019-04-29 17:39:05 +02:00
|
|
|
return PropertyValue(&activity);
|
|
|
|
|
}
|
2018-12-26 20:03:31 +01:00
|
|
|
|
|
|
|
|
else if (stringEqual(property, "actual_fall_transition_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlewProperty(port, RiseFall::fall(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "actual_fall_transition_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlewProperty(port, RiseFall::fall(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "actual_rise_transition_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlewProperty(port, RiseFall::rise(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "actual_rise_transition_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlewProperty(port, RiseFall::rise(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
|
|
|
|
|
else if (stringEqual(property, "min_fall_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlackProperty(port, RiseFall::fall(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "max_fall_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlackProperty(port, RiseFall::fall(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "min_rise_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlackProperty(port, RiseFall::rise(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "max_rise_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return portSlackProperty(port, RiseFall::rise(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("port", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PropertyValue
|
|
|
|
|
portSlewProperty(const Port *port,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
2018-12-26 20:03:31 +01:00
|
|
|
Instance *top_inst = network->topInstance();
|
|
|
|
|
Pin *pin = network->findPin(top_inst, port);
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlewProperty(pin, rf, min_max, sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PropertyValue
|
|
|
|
|
portSlackProperty(const Port *port,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
2018-12-26 20:03:31 +01:00
|
|
|
Instance *top_inst = network->topInstance();
|
|
|
|
|
Pin *pin = network->findPin(top_inst, port);
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlackProperty(pin, rf, min_max, sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const LibertyPort *port,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
2019-06-19 16:55:04 +02:00
|
|
|
Sta *sta)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
if (stringEqual(property, "name"))
|
|
|
|
|
return PropertyValue(port->name());
|
|
|
|
|
else if (stringEqual(property, "full_name"))
|
|
|
|
|
return PropertyValue(port->name());
|
|
|
|
|
else if (stringEqual(property, "direction"))
|
|
|
|
|
return PropertyValue(port->direction()->name());
|
2019-06-19 16:55:04 +02:00
|
|
|
else if (stringEqual(property, "capacitance")) {
|
2019-11-11 23:30:19 +01:00
|
|
|
float cap = port->capacitance(RiseFall::rise(), MinMax::max());
|
2019-06-19 16:55:04 +02:00
|
|
|
return PropertyValue(sta->units()->capacitanceUnit()->asString(cap, 6));
|
|
|
|
|
}
|
2019-06-24 04:52:29 +02:00
|
|
|
else if (stringEqual(property, "drive_resistance_rise_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return PropertyValue(port->driveResistance(RiseFall::rise(),
|
2019-06-24 04:52:29 +02:00
|
|
|
MinMax::min()));
|
|
|
|
|
else if (stringEqual(property, "drive_resistance_rise_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return PropertyValue(port->driveResistance(RiseFall::rise(),
|
2019-06-24 04:52:29 +02:00
|
|
|
MinMax::max()));
|
|
|
|
|
else if (stringEqual(property, "drive_resistance_fall_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return PropertyValue(port->driveResistance(RiseFall::fall(),
|
2019-06-24 04:52:29 +02:00
|
|
|
MinMax::min()));
|
|
|
|
|
else if (stringEqual(property, "drive_resistance_fall_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return PropertyValue(port->driveResistance(RiseFall::fall(),
|
2019-06-24 04:52:29 +02:00
|
|
|
MinMax::max()));
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("liberty port", property);
|
2019-01-17 00:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const Instance *inst,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
2019-01-17 00:37:31 +01:00
|
|
|
Sta *sta)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
if (stringEqual(property, "name"))
|
|
|
|
|
return PropertyValue(network->name(inst));
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "full_name"))
|
2019-01-17 00:37:31 +01:00
|
|
|
return PropertyValue(network->pathName(inst));
|
|
|
|
|
else if (stringEqual(property, "ref_name"))
|
|
|
|
|
return PropertyValue(network->name(network->cell(inst)));
|
|
|
|
|
else if (stringEqual(property, "liberty_cell"))
|
|
|
|
|
return PropertyValue(network->libertyCell(inst));
|
|
|
|
|
else if (stringEqual(property, "cell"))
|
|
|
|
|
return PropertyValue(network->cell(inst));
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("instance", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const Pin *pin,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
if (stringEqual(property, "direction"))
|
|
|
|
|
return PropertyValue(network->direction(pin)->name());
|
2019-07-01 02:17:03 +02:00
|
|
|
else if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name"))
|
2019-01-17 00:37:31 +01:00
|
|
|
return PropertyValue(network->pathName(pin));
|
|
|
|
|
else if (stringEqual(property, "lib_pin_name"))
|
|
|
|
|
return PropertyValue(network->portName(pin));
|
|
|
|
|
else if (stringEqual(property, "clocks")) {
|
|
|
|
|
ClockSet clks;
|
|
|
|
|
sta->clocks(pin, clks);
|
|
|
|
|
return PropertyValue(&clks);
|
|
|
|
|
}
|
2019-04-29 17:39:05 +02:00
|
|
|
else if (stringEqual(property, "activity")) {
|
2019-05-08 22:23:59 +02:00
|
|
|
PwrActivity activity = sta->power()->findClkedActivity(pin);
|
2019-04-29 17:39:05 +02:00
|
|
|
return PropertyValue(&activity);
|
|
|
|
|
}
|
2019-01-17 00:37:31 +01:00
|
|
|
|
|
|
|
|
else if (stringEqual(property, "max_fall_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlackProperty(pin, RiseFall::fall(), MinMax::max(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "max_rise_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlackProperty(pin, RiseFall::rise(), MinMax::max(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "min_fall_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlackProperty(pin, RiseFall::fall(), MinMax::min(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "min_rise_slack"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlackProperty(pin, RiseFall::rise(), MinMax::min(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
|
|
|
|
|
else if (stringEqual(property, "actual_fall_transition_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlewProperty(pin, RiseFall::fall(), MinMax::max(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "actual_rise_transition_max"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlewProperty(pin, RiseFall::rise(), MinMax::max(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "actual_rise_transition_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlewProperty(pin, RiseFall::rise(), MinMax::min(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
else if (stringEqual(property, "actual_fall_transition_min"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return pinSlewProperty(pin, RiseFall::fall(), MinMax::min(), sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("pin", property);
|
2019-01-17 00:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PropertyValue
|
|
|
|
|
pinSlackProperty(const Pin *pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2019-01-17 00:37:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-11-11 23:30:19 +01:00
|
|
|
Slack slack = sta->pinSlack(pin, rf, min_max);
|
2019-01-17 00:37:31 +01:00
|
|
|
return PropertyValue(delayPropertyValue(slack, sta));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PropertyValue
|
|
|
|
|
pinSlewProperty(const Pin *pin,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2019-01-17 00:37:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-05-26 02:08:53 +02:00
|
|
|
auto graph = sta->ensureGraph();
|
2019-01-17 00:37:31 +01:00
|
|
|
Vertex *vertex, *bidirect_drvr_vertex;
|
|
|
|
|
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
|
|
|
|
Slew slew = min_max->initValue();
|
|
|
|
|
if (vertex) {
|
2019-11-11 23:30:19 +01:00
|
|
|
Slew vertex_slew = sta->vertexSlew(vertex, rf, min_max);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (fuzzyGreater(vertex_slew, slew, min_max))
|
2019-01-17 00:37:31 +01:00
|
|
|
slew = vertex_slew;
|
|
|
|
|
}
|
|
|
|
|
if (bidirect_drvr_vertex) {
|
2019-11-11 23:30:19 +01:00
|
|
|
Slew vertex_slew = sta->vertexSlew(bidirect_drvr_vertex, rf, min_max);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (fuzzyGreater(vertex_slew, slew, min_max))
|
2019-01-17 00:37:31 +01:00
|
|
|
slew = vertex_slew;
|
|
|
|
|
}
|
|
|
|
|
return PropertyValue(delayPropertyValue(slew, sta));
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue
|
2019-01-17 00:37:31 +01:00
|
|
|
getProperty(const Net *net,
|
2018-12-26 20:03:31 +01:00
|
|
|
const char *property,
|
2019-01-17 00:37:31 +01:00
|
|
|
Sta *sta)
|
2018-12-26 20:03:31 +01:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
auto network = sta->cmdNetwork();
|
2019-06-01 17:07:38 +02:00
|
|
|
if (stringEqual(property, "name"))
|
|
|
|
|
return PropertyValue(network->name(net));
|
|
|
|
|
else if (stringEqual(property, "full_name"))
|
2019-01-17 00:37:31 +01:00
|
|
|
return PropertyValue(network->pathName(net));
|
2018-12-26 20:03:31 +01:00
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("net", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
|
|
|
|
getProperty(Edge *edge,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
if (stringEqual(property, "full_name")) {
|
|
|
|
|
auto network = sta->cmdNetwork();
|
|
|
|
|
auto graph = sta->graph();
|
|
|
|
|
const char *from = edge->from(graph)->name(network);
|
|
|
|
|
const char *to = edge->to(graph)->name(network);
|
|
|
|
|
return stringPrintTmp("%s -> %s", from, to);
|
|
|
|
|
}
|
2018-12-26 20:03:31 +01:00
|
|
|
if (stringEqual(property, "delay_min_fall"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return edgeDelayProperty(edge, RiseFall::fall(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "delay_max_fall"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return edgeDelayProperty(edge, RiseFall::fall(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "delay_min_rise"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return edgeDelayProperty(edge, RiseFall::rise(), MinMax::min(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "delay_max_rise"))
|
2019-11-11 23:30:19 +01:00
|
|
|
return edgeDelayProperty(edge, RiseFall::rise(), MinMax::max(), sta);
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "sense"))
|
|
|
|
|
return PropertyValue(timingSenseString(edge->sense()));
|
|
|
|
|
else if (stringEqual(property, "from_pin"))
|
|
|
|
|
return PropertyValue(edge->from(sta->graph())->pin());
|
|
|
|
|
else if (stringEqual(property, "to_pin"))
|
|
|
|
|
return PropertyValue(edge->to(sta->graph())->pin());
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("edge", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PropertyValue
|
|
|
|
|
edgeDelayProperty(Edge *edge,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *rf,
|
2018-12-26 20:03:31 +01:00
|
|
|
const MinMax *min_max,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
|
|
|
|
ArcDelay delay = 0.0;
|
|
|
|
|
bool delay_exists = false;
|
|
|
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
|
|
|
TimingArcSetArcIterator arc_iter(arc_set);
|
|
|
|
|
while (arc_iter.hasNext()) {
|
|
|
|
|
TimingArc *arc = arc_iter.next();
|
2019-11-11 23:30:19 +01:00
|
|
|
RiseFall *to_rf = arc->toTrans()->asRiseFall();
|
|
|
|
|
if (to_rf == rf) {
|
2019-07-18 15:19:00 +02:00
|
|
|
for (auto corner : *sta->corners()) {
|
2018-12-26 20:03:31 +01:00
|
|
|
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
|
|
|
|
ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap);
|
|
|
|
|
if (!delay_exists
|
|
|
|
|
|| ((min_max == MinMax::max()
|
|
|
|
|
&& arc_delay > delay)
|
|
|
|
|
|| (min_max == MinMax::min()
|
|
|
|
|
&& arc_delay < delay)))
|
|
|
|
|
delay = arc_delay;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return PropertyValue(delayPropertyValue(delay, sta));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
PropertyValue
|
|
|
|
|
getProperty(TimingArcSet *arc_set,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *)
|
|
|
|
|
{
|
|
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name")) {
|
|
|
|
|
auto from = arc_set->from()->name();
|
|
|
|
|
auto to = arc_set->to()->name();
|
|
|
|
|
auto cell_name = arc_set->libertyCell()->name();
|
|
|
|
|
string name;
|
|
|
|
|
stringPrint(name, "%s %s -> %s", cell_name, from, to);
|
|
|
|
|
return PropertyValue(name);
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("timing arc", property);
|
2019-01-17 00:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-12-26 20:03:31 +01:00
|
|
|
PropertyValue
|
|
|
|
|
getProperty(Clock *clk,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
if (stringEqual(property, "name")
|
|
|
|
|
|| stringEqual(property, "full_name"))
|
2018-12-26 20:03:31 +01:00
|
|
|
return PropertyValue(clk->name());
|
|
|
|
|
else if (stringEqual(property, "period"))
|
2019-06-19 16:55:04 +02:00
|
|
|
return PropertyValue(sta->units()->timeUnit()->asString(clk->period(), 6));
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "sources"))
|
2019-10-25 17:51:59 +02:00
|
|
|
return PropertyValue(&clk->pins());
|
2018-12-26 20:03:31 +01:00
|
|
|
else if (stringEqual(property, "propagated"))
|
|
|
|
|
return PropertyValue(clk->isPropagated() ? "1" : "0");
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("clock", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
|
|
|
|
getProperty(PathEnd *end,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
|
|
|
|
if (stringEqual(property, "startpoint")) {
|
|
|
|
|
PathExpanded expanded(end->path(), sta);
|
|
|
|
|
return PropertyValue(expanded.startPath()->pin(sta));
|
|
|
|
|
}
|
|
|
|
|
else if (stringEqual(property, "startpoint_clock"))
|
|
|
|
|
return PropertyValue(end->path()->clock(sta));
|
|
|
|
|
else if (stringEqual(property, "endpoint"))
|
|
|
|
|
return PropertyValue(end->path()->pin(sta));
|
|
|
|
|
else if (stringEqual(property, "endpoint_clock"))
|
|
|
|
|
return PropertyValue(end->targetClk(sta));
|
|
|
|
|
else if (stringEqual(property, "endpoint_clock_pin"))
|
|
|
|
|
return PropertyValue(end->targetClkPath()->pin(sta));
|
|
|
|
|
else if (stringEqual(property, "slack"))
|
|
|
|
|
return PropertyValue(delayPropertyValue(end->slack(sta), sta));
|
|
|
|
|
else if (stringEqual(property, "points")) {
|
|
|
|
|
PathExpanded expanded(end->path(), sta);
|
|
|
|
|
PathRefSeq paths;
|
|
|
|
|
for (auto i = expanded.startIndex(); i < expanded.size(); i++) {
|
|
|
|
|
PathRef *path = expanded.path(i);
|
|
|
|
|
paths.push_back(*path);
|
|
|
|
|
}
|
|
|
|
|
return PropertyValue(&paths);
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("path end", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyValue
|
|
|
|
|
getProperty(PathRef *path,
|
|
|
|
|
const char *property,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
|
|
|
|
if (stringEqual(property, "pin"))
|
|
|
|
|
return PropertyValue(path->pin(sta));
|
|
|
|
|
else if (stringEqual(property, "arrival"))
|
|
|
|
|
return PropertyValue(delayPropertyValue(path->arrival(sta), sta));
|
|
|
|
|
else if (stringEqual(property, "required"))
|
|
|
|
|
return PropertyValue(delayPropertyValue(path->required(sta), sta));
|
|
|
|
|
else if (stringEqual(property, "slack"))
|
|
|
|
|
return PropertyValue(delayPropertyValue(path->slack(sta), sta));
|
|
|
|
|
else
|
2019-02-17 00:31:39 +01:00
|
|
|
throw PropertyUnknown("path", property);
|
2018-12-26 20:03:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static float
|
|
|
|
|
delayPropertyValue(Delay delay,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
|
|
|
|
return delayAsFloat(delay) / sta->units()->timeUnit()->scale();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|