Files
OpenSTA/sdf/SdfReader.cc
T

1043 lines
30 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.
2026-03-15 14:35:24 -07:00
//
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.
2026-03-15 14:35:24 -07:00
//
2018-09-28 08:54:21 -07:00
// 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.
2026-03-15 14:35:24 -07:00
//
2018-09-28 08:54:21 -07:00
// 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/>.
2026-03-15 14:35:24 -07:00
//
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.
2026-03-15 14:35:24 -07:00
//
2025-01-21 18:54:33 -07:00
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
2026-03-15 14:35:24 -07:00
//
2025-01-21 18:54:33 -07:00
// This notice may not be removed or altered from any source distribution.
2018-09-28 08:54:21 -07:00
2020-04-05 11:35:51 -07:00
#include "sdf/SdfReader.hh"
2023-06-15 08:59:56 -07:00
#include <cctype>
2026-04-15 09:38:10 -07:00
#include <cstdarg>
2026-03-02 12:13:13 -08:00
#include <string>
2026-03-28 19:13:35 -07:00
#include <utility>
2020-04-05 11:35:51 -07:00
2026-01-03 16:59:35 -08:00
#include "ContainerHelpers.hh"
2023-02-18 17:20:40 -07:00
#include "Debug.hh"
2026-04-15 09:38:10 -07:00
#include "Error.hh"
#include "Graph.hh"
2020-04-05 14:53:44 -07:00
#include "MinMax.hh"
#include "Network.hh"
2026-04-15 09:38:10 -07:00
#include "Report.hh"
2026-01-03 16:59:35 -08:00
#include "Scene.hh"
2021-11-08 13:39:23 -07:00
#include "Sdc.hh"
2026-04-15 09:38:10 -07:00
#include "SdcNetwork.hh"
#include "Stats.hh"
#include "TimingArc.hh"
#include "Zlib.hh"
2021-11-08 13:39:23 -07:00
#include "sdf/SdfReaderPvt.hh"
2025-01-25 11:34:04 -07:00
#include "sdf/SdfScanner.hh"
2018-09-28 08:54:21 -07:00
namespace sta {
class SdfTriple
{
public:
SdfTriple(float *min,
2026-01-03 16:59:35 -08:00
float *typ,
float *max);
2018-09-28 08:54:21 -07:00
~SdfTriple();
float **values() { return values_; }
bool hasValue() const;
private:
float *values_[3];
};
class SdfPortSpec
{
public:
2025-01-25 11:34:04 -07:00
SdfPortSpec(const Transition *tr,
2026-03-28 19:13:35 -07:00
std::string_view port,
std::string_view cond);
std::string_view port() const { return port_; }
2025-01-25 11:34:04 -07:00
const Transition *transition() const { return tr_; }
2026-03-28 19:13:35 -07:00
std::string_view cond() const { return cond_; }
2018-09-28 08:54:21 -07:00
private:
2025-01-25 11:34:04 -07:00
const Transition *tr_;
2026-03-28 19:13:35 -07:00
const std::string port_;
const std::string cond_; // timing checks only
2018-09-28 08:54:21 -07:00
};
bool
2026-03-28 19:13:35 -07:00
readSdf(std::string_view filename,
std::string_view path,
2026-01-03 16:59:35 -08:00
Scene *scene,
2021-11-08 13:39:23 -07:00
bool unescaped_dividers,
bool incremental_only,
MinMaxAll *cond_use,
StaState *sta)
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
int arc_min_index = scene->dcalcAnalysisPtIndex(MinMax::min());
int arc_max_index = scene->dcalcAnalysisPtIndex(MinMax::max());
2026-03-15 14:35:24 -07:00
SdfReader reader(filename, path, arc_min_index, arc_max_index,
scene->sdc()->analysisType(), unescaped_dividers,
incremental_only, cond_use, sta);
2022-01-13 11:49:01 -07:00
bool success = reader.read();
return success;
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
SdfReader::SdfReader(std::string_view filename,
std::string_view path,
2018-09-28 08:54:21 -07:00
int arc_min_index,
2026-01-03 16:59:35 -08:00
int arc_max_index,
AnalysisType analysis_type,
bool unescaped_dividers,
bool is_incremental_only,
2018-09-28 08:54:21 -07:00
MinMaxAll *cond_use,
2026-01-03 16:59:35 -08:00
StaState *sta) :
2018-09-28 08:54:21 -07:00
StaState(sta),
filename_(filename),
path_(path),
arc_delay_min_index_(arc_min_index),
arc_delay_max_index_(arc_max_index),
analysis_type_(analysis_type),
unescaped_dividers_(unescaped_dividers),
is_incremental_only_(is_incremental_only),
2026-04-15 09:38:10 -07:00
cond_use_(cond_use)
2018-09-28 08:54:21 -07:00
{
if (unescaped_dividers)
network_ = makeSdcNetwork(network_);
}
SdfReader::~SdfReader()
{
if (unescaped_dividers_)
delete network_;
}
bool
SdfReader::read()
{
2026-03-28 19:13:35 -07:00
gzstream::igzstream stream(std::string(filename_).c_str());
2025-01-27 08:33:35 -07:00
if (stream.is_open()) {
2025-01-25 11:34:04 -07:00
Stats stats(debug_, report_);
SdfScanner scanner(&stream, filename_, this, report_);
scanner_ = &scanner;
SdfParse parser(&scanner, this);
bool success = (parser.parse() == 0);
stats.report("Read sdf");
2018-09-28 08:54:21 -07:00
return success;
}
else
2026-03-15 14:35:24 -07:00
throw FileNotReadable(filename_);
2018-09-28 08:54:21 -07:00
}
void
SdfReader::setDivider(char divider)
{
divider_ = divider;
}
void
SdfReader::setTimescale(float multiplier,
2026-03-28 19:13:35 -07:00
std::string_view units)
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
if (multiplier == 1.0 || multiplier == 10.0 || multiplier == 100.0) {
2026-03-28 19:13:35 -07:00
if (units == "us")
2018-09-28 08:54:21 -07:00
timescale_ = multiplier * 1E-6F;
2026-03-28 19:13:35 -07:00
else if (units == "ns")
2018-09-28 08:54:21 -07:00
timescale_ = multiplier * 1E-9F;
2026-03-28 19:13:35 -07:00
else if (units == "ps")
2018-09-28 08:54:21 -07:00
timescale_ = multiplier * 1E-12F;
else
2026-03-15 14:35:24 -07:00
error(180, "TIMESCALE units not us, ns, or ps.");
2018-09-28 08:54:21 -07:00
}
else
2026-03-15 14:35:24 -07:00
error(181, "TIMESCALE multiplier not 1, 10, or 100.");
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
SdfReader::interconnect(std::string_view from_pin_name,
std::string_view to_pin_name,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
if (!(is_incremental_only_ && !in_incremental_)) {
Pin *from_pin = findPin(from_pin_name);
Pin *to_pin = findPin(to_pin_name);
if (from_pin && to_pin) {
// Assume the pins are non-hierarchical and on the same net.
Edge *edge = findWireEdge(from_pin, to_pin);
if (edge)
2026-01-03 16:59:35 -08:00
setEdgeDelays(edge, triples, "INTERCONNECT");
2018-09-28 08:54:21 -07:00
else {
2026-01-03 16:59:35 -08:00
bool from_is_hier = network_->isHierarchical(from_pin);
bool to_is_hier = network_->isHierarchical(to_pin);
if (from_is_hier || to_is_hier) {
if (from_is_hier)
2026-03-28 19:13:35 -07:00
error(182, "pin {} is a hierarchical pin.", from_pin_name);
2026-01-03 16:59:35 -08:00
if (to_is_hier)
2026-03-28 19:13:35 -07:00
error(183, "pin {} is a hierarchical pin.", to_pin_name);
2026-01-03 16:59:35 -08:00
}
else
2026-03-15 14:35:24 -07:00
warn(184, "INTERCONNECT from {} to {} not found.",
2026-03-28 19:13:35 -07:00
from_pin_name, to_pin_name);
2018-09-28 08:54:21 -07:00
}
}
else {
2019-03-12 17:25:53 -07:00
if (from_pin == nullptr)
2026-03-28 19:13:35 -07:00
warn(185, "pin {} not found.", from_pin_name);
2019-03-12 17:25:53 -07:00
if (to_pin == nullptr)
2026-03-28 19:13:35 -07:00
warn(186, "pin {} not found.", to_pin_name);
2018-09-28 08:54:21 -07:00
}
}
deleteTripleSeq(triples);
}
void
2026-03-28 19:13:35 -07:00
SdfReader::port(std::string_view to_pin_name,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
if (!(is_incremental_only_ && !in_incremental_)) {
Pin *to_pin = (instance_)
2026-03-28 19:13:35 -07:00
? network_->findPinRelative(instance_, to_pin_name)
: network_->findPin(to_pin_name);
2019-03-12 17:25:53 -07:00
if (to_pin == nullptr)
2026-03-28 19:13:35 -07:00
warn(187, "pin {} not found.", to_pin_name);
2018-09-28 08:54:21 -07:00
else {
Vertex *vertex = graph_->pinLoadVertex(to_pin);
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
2026-01-03 16:59:35 -08:00
Edge *edge = edge_iter.next();
if (edge->role()->sdfRole()->isWire())
setEdgeDelays(edge, triples, "PORT");
2018-09-28 08:54:21 -07:00
}
}
}
deleteTripleSeq(triples);
}
Edge *
SdfReader::findWireEdge(Pin *from_pin,
2026-01-03 16:59:35 -08:00
Pin *to_pin)
2018-09-28 08:54:21 -07:00
{
Vertex *to_vertex, *to_vertex_bidirect_drvr;
graph_->pinVertices(to_pin, to_vertex, to_vertex_bidirect_drvr);
2022-09-05 21:28:47 -07:00
if (to_vertex) {
// Fanin < fanout, so search for driver from load.
VertexInEdgeIterator edge_iter(to_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
const TimingRole *edge_role = edge->role();
2026-03-15 14:35:24 -07:00
if (edge->from(graph_)->pin() == from_pin && edge_role->sdfRole()->isWire())
2022-09-05 21:28:47 -07:00
return edge;
}
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
void
SdfReader::setEdgeDelays(Edge *edge,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples,
2026-03-28 19:13:35 -07:00
std::string_view sdf_cmd)
2018-09-28 08:54:21 -07:00
{
// Rise/fall triples.
size_t triple_count = triples->size();
2026-03-15 14:35:24 -07:00
if (triple_count == 1 || triple_count == 2) {
2018-09-28 08:54:21 -07:00
TimingArcSet *arc_set = edge->timingArcSet();
2022-06-12 11:47:26 -07:00
for (TimingArc *arc : arc_set->arcs()) {
2018-09-28 08:54:21 -07:00
size_t triple_index;
if (triple_count == 1)
2026-01-03 16:59:35 -08:00
triple_index = 0;
2018-09-28 08:54:21 -07:00
else
2026-01-03 16:59:35 -08:00
triple_index = arc->toEdge()->sdfTripleIndex();
2018-09-28 08:54:21 -07:00
SdfTriple *triple = (*triples)[triple_index];
setEdgeArcDelays(edge, arc, triple);
}
}
else if (triple_count == 0)
2026-03-15 14:35:24 -07:00
error(188, "{} with no triples.", sdf_cmd);
2018-09-28 08:54:21 -07:00
else
2026-03-15 14:35:24 -07:00
error(189, "{} with more than 2 triples.", sdf_cmd);
2018-09-28 08:54:21 -07:00
}
void
2026-03-28 19:13:35 -07:00
SdfReader::setCell(std::string_view cell_name)
2018-09-28 08:54:21 -07:00
{
cell_name_ = cell_name;
}
void
2026-03-28 19:13:35 -07:00
SdfReader::setInstance()
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
instance_ = nullptr;
}
void
SdfReader::setInstance(std::string_view instance_name)
{
if (instance_name == "*") {
warn(193, "INSTANCE wildcards not supported.");
instance_ = nullptr;
}
else {
instance_ = findInstance(instance_name);
if (instance_) {
Cell *inst_cell = network_->cell(instance_);
std::string inst_cell_name(network_->name(inst_cell));
if (inst_cell_name != cell_name_)
warn(190, "instance {} cell {} does not match enclosing cell {}.",
instance_name,
inst_cell_name,
cell_name_);
2018-09-28 08:54:21 -07:00
}
}
}
void
SdfReader::setInstanceWildcard()
{
2026-03-28 19:13:35 -07:00
warn(172, "INSTANCE wildcards not supported.");
2019-03-12 17:25:53 -07:00
instance_ = nullptr;
2018-09-28 08:54:21 -07:00
}
void
SdfReader::cellFinish()
{
2026-03-28 19:13:35 -07:00
cell_name_.clear();
2019-03-12 17:25:53 -07:00
instance_ = nullptr;
2018-09-28 08:54:21 -07:00
}
void
SdfReader::iopath(SdfPortSpec *from_edge,
2026-03-28 19:13:35 -07:00
std::string_view to_port_name,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples,
2026-03-28 19:13:35 -07:00
std::string_view cond,
2026-01-03 16:59:35 -08:00
bool condelse)
2018-09-28 08:54:21 -07:00
{
if (instance_) {
2026-03-28 19:13:35 -07:00
std::string_view from_port_name = from_edge->port();
2018-09-28 08:54:21 -07:00
Cell *cell = network_->cell(instance_);
2023-02-18 17:20:40 -07:00
Port *from_port = findPort(cell, from_port_name);
Port *to_port = findPort(cell, to_port_name);
2018-09-28 08:54:21 -07:00
if (from_port && to_port) {
2025-01-25 11:34:04 -07:00
Pin *from_pin = network_->findPin(instance_, from_port);
Pin *to_pin = network_->findPin(instance_, to_port);
2018-09-28 08:54:21 -07:00
// Do not report an error if the pin is not found because the
// instance may not have the pin.
if (from_pin && to_pin) {
2026-01-03 16:59:35 -08:00
Vertex *to_vertex = graph_->pinDrvrVertex(to_pin);
if (to_vertex) {
2022-01-15 12:51:05 -07:00
size_t triple_count = triples->size();
bool matched = false;
// Fanin < fanout, so search for driver from load.
// Search for multiple matching edges because of
// tristate enable/disable.
VertexInEdgeIterator edge_iter(to_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
2026-02-04 18:33:04 -07:00
const std::string &lib_cond = arc_set->sdfCond();
2022-01-15 12:51:05 -07:00
const TimingRole *edge_role = arc_set->role();
2026-03-28 19:13:35 -07:00
bool cond_use_flag = cond_use_ && !cond.empty() && lib_cond.empty()
&& !(!is_incremental_only_ && in_incremental_);
2022-01-15 12:51:05 -07:00
if (edge->from(graph_)->pin() == from_pin
&& edge_role->sdfRole() == TimingRole::sdfIopath()
&& (cond_use_flag
|| (!condelse && condMatch(cond, lib_cond))
// condelse matches the default (unconditional) arc.
2026-02-04 18:33:04 -07:00
|| (condelse && lib_cond.empty()))) {
2022-01-15 12:51:05 -07:00
matched = true;
2022-06-12 11:47:26 -07:00
for (TimingArc *arc : arc_set->arcs()) {
2022-01-15 12:51:05 -07:00
if ((from_edge->transition() == Transition::riseFall())
2022-02-13 17:46:45 -07:00
|| (arc->fromEdge() == from_edge->transition())) {
size_t triple_index = arc->toEdge()->sdfTripleIndex();
2022-01-15 12:51:05 -07:00
SdfTriple *triple = nullptr;
if (triple_index < triple_count)
triple = (*triples)[triple_index];
if (triple_count == 1)
triple = (*triples)[0];
// Rules for matching when triple is missing not implemented.
// See SDF pg 3-17.
if (triple) {
if (cond_use_flag)
setEdgeArcDelaysCondUse(edge, arc, triple);
else
setEdgeArcDelays(edge, arc, triple);
}
}
}
}
}
if (!matched)
2026-03-15 14:35:24 -07:00
warn(191, "cell {} IOPATH {} -> {} not found.",
2026-03-28 19:13:35 -07:00
network_->cellName(instance_),
from_port_name,
to_port_name);
2022-01-15 12:51:05 -07:00
}
2018-09-28 08:54:21 -07:00
}
}
}
2025-01-25 11:34:04 -07:00
delete from_edge;
2018-09-28 08:54:21 -07:00
deleteTripleSeq(triples);
2023-02-18 17:20:40 -07:00
}
Port *
SdfReader::findPort(const Cell *cell,
2026-03-28 19:13:35 -07:00
std::string_view port_name)
2023-02-18 17:20:40 -07:00
{
2026-03-28 19:13:35 -07:00
Port *port = network_->findPort(cell, port_name);
2023-02-18 17:20:40 -07:00
if (port == nullptr)
2026-03-15 14:35:24 -07:00
warn(194, "instance {} port {} not found.", network_->pathName(instance_),
2026-03-28 19:13:35 -07:00
port_name);
2023-02-18 17:20:40 -07:00
return port;
2018-09-28 08:54:21 -07:00
}
void
2025-03-30 15:27:53 -07:00
SdfReader::timingCheck(const TimingRole *role,
2024-07-14 18:29:48 -07:00
SdfPortSpec *data_edge,
2026-01-03 16:59:35 -08:00
SdfPortSpec *clk_edge,
2024-07-14 18:29:48 -07:00
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
2024-07-13 17:08:43 -07:00
if (instance_) {
2026-03-28 19:13:35 -07:00
std::string_view data_port_name = data_edge->port();
std::string_view clk_port_name = clk_edge->port();
2024-07-13 17:08:43 -07:00
Cell *cell = network_->cell(instance_);
Port *data_port = findPort(cell, data_port_name);
Port *clk_port = findPort(cell, clk_port_name);
if (data_port && clk_port)
timingCheck1(role, data_port, data_edge, clk_port, clk_edge, triple);
}
2025-01-25 11:34:04 -07:00
delete data_edge;
delete clk_edge;
2018-09-28 08:54:21 -07:00
deleteTriple(triple);
}
void
2025-03-30 15:27:53 -07:00
SdfReader::timingCheck1(const TimingRole *role,
2023-02-18 17:20:40 -07:00
Port *data_port,
2026-01-03 16:59:35 -08:00
SdfPortSpec *data_edge,
2023-02-18 17:20:40 -07:00
Port *clk_port,
2026-01-03 16:59:35 -08:00
SdfPortSpec *clk_edge,
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
2026-03-15 14:35:24 -07:00
if (!(is_incremental_only_ && !in_incremental_) && instance_) {
2023-02-18 17:20:40 -07:00
Pin *data_pin = network_->findPin(instance_, data_port);
Pin *clk_pin = network_->findPin(instance_, clk_port);
if (data_pin && clk_pin) {
// Hack: always use triple max value for check.
float **values = triple->values();
float *value_min = values[triple_min_index_];
float *value_max = values[triple_max_index_];
if (value_min && value_max) {
switch (analysis_type_) {
2026-03-15 14:35:24 -07:00
case AnalysisType::single:
break;
case AnalysisType::bc_wc:
if (role->genericRole() == TimingRole::setup())
*value_min = *value_max;
else
*value_max = *value_min;
break;
case AnalysisType::ocv:
2021-11-08 13:39:23 -07:00
*value_min = *value_max;
2026-03-15 14:35:24 -07:00
break;
2021-11-08 13:39:23 -07:00
}
2018-09-28 08:54:21 -07:00
}
2026-03-15 14:35:24 -07:00
bool matched = annotateCheckEdges(data_pin, data_edge, clk_pin, clk_edge, role,
2023-02-18 17:20:40 -07:00
triple, false);
// Liberty setup/hold checks on preset/clear pins can be translated
// into recovery/removal checks, so be flexible about matching.
if (!matched)
2026-03-15 14:35:24 -07:00
matched = annotateCheckEdges(data_pin, data_edge, clk_pin, clk_edge, role,
2023-02-18 17:20:40 -07:00
triple, true);
if (!matched
// Only warn when non-null values are present.
&& triple->hasValue())
2026-03-15 14:35:24 -07:00
warn(192, "cell {} {} -> {} {} check not found.",
network_->cellName(instance_), network_->name(data_port),
network_->name(clk_port), role->to_string());
2018-09-28 08:54:21 -07:00
}
}
}
// Return true if matched.
bool
SdfReader::annotateCheckEdges(Pin *data_pin,
2026-01-03 16:59:35 -08:00
SdfPortSpec *data_edge,
Pin *clk_pin,
SdfPortSpec *clk_edge,
const TimingRole *sdf_role,
SdfTriple *triple,
bool match_generic)
2018-09-28 08:54:21 -07:00
{
bool matched = false;
2026-03-28 19:13:35 -07:00
std::string_view cond_start = data_edge->cond();
std::string_view cond_end = clk_edge->cond();
2018-09-28 08:54:21 -07:00
// Timing check graph edges from clk to data.
Vertex *to_vertex = graph_->pinLoadVertex(data_pin);
// Fanin < fanout, so search for driver from load.
VertexInEdgeIterator edge_iter(to_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->from(graph_)->pin() == clk_pin) {
TimingArcSet *arc_set = edge->timingArcSet();
const TimingRole *edge_role = arc_set->role();
2026-03-28 19:13:35 -07:00
std::string_view lib_cond_start = arc_set->sdfCondStart();
std::string_view lib_cond_end = arc_set->sdfCondEnd();
2026-03-15 14:35:24 -07:00
bool cond_matches =
2026-03-28 19:13:35 -07:00
condMatch(cond_start, lib_cond_start) && condMatch(cond_end, lib_cond_end);
2018-09-28 08:54:21 -07:00
if (((!match_generic && edge_role->sdfRole() == sdf_role)
2026-03-15 14:35:24 -07:00
|| (match_generic && edge_role->genericRole() == sdf_role->genericRole()))
2026-01-03 16:59:35 -08:00
&& cond_matches) {
TimingArcSet *arc_set = edge->timingArcSet();
2022-06-12 11:47:26 -07:00
for (TimingArc *arc : arc_set->arcs()) {
2026-01-03 16:59:35 -08:00
if (((data_edge->transition() == Transition::riseFall())
|| (arc->toEdge() == data_edge->transition()))
&& ((clk_edge->transition() == Transition::riseFall())
|| (arc->fromEdge() == clk_edge->transition()))) {
setEdgeArcDelays(edge, arc, triple);
}
}
matched = true;
2018-09-28 08:54:21 -07:00
}
}
}
return matched;
}
void
SdfReader::timingCheckWidth(SdfPortSpec *edge,
2026-01-03 16:59:35 -08:00
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
2026-03-15 14:35:24 -07:00
if (!(is_incremental_only_ && !in_incremental_) && instance_) {
2026-03-28 19:13:35 -07:00
std::string_view port_name = edge->port();
2018-09-28 08:54:21 -07:00
Cell *cell = network_->cell(instance_);
2023-02-18 17:20:40 -07:00
Port *port = findPort(cell, port_name);
if (port) {
2026-03-28 19:13:35 -07:00
Pin *pin = network_->findPin(instance_, port_name);
2018-09-28 08:54:21 -07:00
if (pin) {
const RiseFall *rf = edge->transition()->asRiseFall();
Edge *edge;
TimingArc *arc;
graph_->minPulseWidthArc(graph_->pinLoadVertex(pin), rf, edge, arc);
if (edge)
setEdgeArcDelays(edge, arc, triple);
2018-09-28 08:54:21 -07:00
}
}
}
2025-01-25 11:34:04 -07:00
delete edge;
2018-09-28 08:54:21 -07:00
deleteTriple(triple);
}
2023-02-18 17:20:40 -07:00
void
SdfReader::timingCheckSetupHold(SdfPortSpec *data_edge,
2026-01-03 16:59:35 -08:00
SdfPortSpec *clk_edge,
SdfTriple *setup_triple,
SdfTriple *hold_triple)
2023-02-18 17:20:40 -07:00
{
timingCheckSetupHold1(data_edge, clk_edge, setup_triple, hold_triple,
TimingRole::setup(), TimingRole::hold());
}
void
SdfReader::timingCheckRecRem(SdfPortSpec *data_edge,
2026-01-03 16:59:35 -08:00
SdfPortSpec *clk_edge,
SdfTriple *rec_triple,
SdfTriple *rem_triple)
2023-02-18 17:20:40 -07:00
{
timingCheckSetupHold1(data_edge, clk_edge, rec_triple, rem_triple,
TimingRole::recovery(), TimingRole::removal());
}
void
SdfReader::timingCheckSetupHold1(SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *setup_triple,
SdfTriple *hold_triple,
2025-03-30 15:27:53 -07:00
const TimingRole *setup_role,
const TimingRole *hold_role)
2023-02-18 17:20:40 -07:00
{
2026-03-28 19:13:35 -07:00
std::string_view data_port_name = data_edge->port();
std::string_view clk_port_name = clk_edge->port();
2023-02-18 17:20:40 -07:00
Cell *cell = network_->cell(instance_);
Port *data_port = findPort(cell, data_port_name);
Port *clk_port = findPort(cell, clk_port_name);
if (data_port && clk_port) {
timingCheck1(setup_role, data_port, data_edge, clk_port, clk_edge, setup_triple);
timingCheck1(hold_role, data_port, data_edge, clk_port, clk_edge, hold_triple);
}
2025-01-25 11:34:04 -07:00
delete data_edge;
delete clk_edge;
2023-02-18 17:20:40 -07:00
deleteTriple(setup_triple);
deleteTriple(hold_triple);
}
2018-09-28 08:54:21 -07:00
void
SdfReader::timingCheckPeriod(SdfPortSpec *edge,
2026-01-03 16:59:35 -08:00
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
2026-03-15 14:35:24 -07:00
if (!(is_incremental_only_ && !in_incremental_) && instance_) {
2026-03-28 19:13:35 -07:00
std::string_view port_name = edge->port();
2018-09-28 08:54:21 -07:00
Cell *cell = network_->cell(instance_);
2023-02-18 17:20:40 -07:00
Port *port = findPort(cell, port_name);
if (port) {
2018-09-28 08:54:21 -07:00
// Edge specifier is ignored for period checks.
2026-03-28 19:13:35 -07:00
Pin *pin = network_->findPin(instance_, port_name);
2018-09-28 08:54:21 -07:00
if (pin) {
2026-01-03 16:59:35 -08:00
float **values = triple->values();
float *value_ptr = values[triple_min_index_];
if (value_ptr) {
float value = *value_ptr;
graph_->setPeriodCheckAnnotation(pin, arc_delay_min_index_, value);
}
if (triple_max_index_ != null_index_) {
value_ptr = values[triple_max_index_];
if (value_ptr) {
float value = *value_ptr;
graph_->setPeriodCheckAnnotation(pin, arc_delay_max_index_, value);
}
}
2018-09-28 08:54:21 -07:00
}
}
}
2025-01-25 11:34:04 -07:00
delete edge;
2018-09-28 08:54:21 -07:00
deleteTriple(triple);
}
void
SdfReader::timingCheckNochange(SdfPortSpec *data_edge,
2026-01-03 16:59:35 -08:00
SdfPortSpec *clk_edge,
SdfTriple *before_triple,
SdfTriple *after_triple)
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
warn(173, "NOCHANGE not supported.");
2025-01-25 11:34:04 -07:00
delete data_edge;
delete clk_edge;
2018-09-28 08:54:21 -07:00
deleteTriple(before_triple);
deleteTriple(after_triple);
}
void
SdfReader::device(SdfTripleSeq *triples)
{
// Ignore non-incremental annotations in incremental only mode.
2026-03-15 14:35:24 -07:00
if (!(is_incremental_only_ && !in_incremental_) && instance_) {
2018-09-28 08:54:21 -07:00
InstancePinIterator *pin_iter = network_->pinIterator(instance_);
while (pin_iter->hasNext()) {
Pin *to_pin = pin_iter->next();
setDevicePinDelays(to_pin, triples);
}
delete pin_iter;
}
deleteTripleSeq(triples);
}
void
2026-03-28 19:13:35 -07:00
SdfReader::device(std::string_view to_port_name,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples)
2018-09-28 08:54:21 -07:00
{
// Ignore non-incremental annotations in incremental only mode.
2026-03-15 14:35:24 -07:00
if (!(is_incremental_only_ && !in_incremental_) && instance_) {
2018-09-28 08:54:21 -07:00
Cell *cell = network_->cell(instance_);
2023-02-18 17:20:40 -07:00
Port *to_port = findPort(cell, to_port_name);
if (to_port) {
2026-03-28 19:13:35 -07:00
Pin *to_pin = network_->findPin(instance_, to_port_name);
2018-09-28 08:54:21 -07:00
setDevicePinDelays(to_pin, triples);
}
}
deleteTripleSeq(triples);
}
void
SdfReader::setDevicePinDelays(Pin *to_pin,
2026-01-03 16:59:35 -08:00
SdfTripleSeq *triples)
2018-09-28 08:54:21 -07:00
{
Vertex *vertex = graph_->pinDrvrVertex(to_pin);
2022-01-15 12:51:05 -07:00
if (vertex) {
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->sdfRole() == TimingRole::sdfIopath())
setEdgeDelays(edge, triples, "DEVICE");
}
2018-09-28 08:54:21 -07:00
}
}
void
SdfReader::setEdgeArcDelays(Edge *edge,
2026-01-03 16:59:35 -08:00
TimingArc *arc,
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
setEdgeArcDelays(edge, arc, triple, triple_min_index_, arc_delay_min_index_);
setEdgeArcDelays(edge, arc, triple, triple_max_index_, arc_delay_max_index_);
}
void
SdfReader::setEdgeArcDelays(Edge *edge,
2026-01-03 16:59:35 -08:00
TimingArc *arc,
SdfTriple *triple,
int triple_index,
int arc_delay_index)
2018-09-28 08:54:21 -07:00
{
if (triple_index != null_index_) {
float **values = triple->values();
float *value_ptr = values[triple_index];
if (value_ptr) {
ArcDelay delay;
if (in_incremental_)
2026-03-13 14:06:35 -07:00
delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value_ptr, this);
2018-09-28 08:54:21 -07:00
else
2026-01-03 16:59:35 -08:00
delay = *value_ptr;
2018-09-28 08:54:21 -07:00
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
graph_->setArcDelayAnnotated(edge, arc, arc_delay_index, true);
2018-09-28 08:54:21 -07:00
edge->setDelayAnnotationIsIncremental(is_incremental_only_);
}
}
}
void
SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
2026-01-03 16:59:35 -08:00
TimingArc *arc,
SdfTriple *triple)
2018-09-28 08:54:21 -07:00
{
float **values = triple->values();
2021-11-08 13:39:23 -07:00
float *value_min = values[triple_min_index_];
2021-11-09 11:03:56 -07:00
float *value_max = values[triple_max_index_];
2025-03-30 15:27:53 -07:00
const MinMax *min, *max;
2018-09-28 08:54:21 -07:00
if (cond_use_ == MinMaxAll::min()) {
min = MinMax::min();
max = MinMax::min();
}
else if (cond_use_ == MinMaxAll::max()) {
min = MinMax::max();
max = MinMax::max();
}
else {
min = MinMax::min();
max = MinMax::max();
}
setEdgeArcDelaysCondUse(edge, arc, value_min, triple_min_index_,
2026-01-03 16:59:35 -08:00
arc_delay_min_index_, min);
2018-09-28 08:54:21 -07:00
setEdgeArcDelaysCondUse(edge, arc, value_max, triple_max_index_,
2026-01-03 16:59:35 -08:00
arc_delay_max_index_, max);
2018-09-28 08:54:21 -07:00
}
void
SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
2026-01-03 16:59:35 -08:00
TimingArc *arc,
2026-04-15 09:38:10 -07:00
const float *value,
2026-01-03 16:59:35 -08:00
int triple_index,
int arc_delay_index,
const MinMax *min_max)
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
if (value && triple_index != null_index_) {
2018-09-28 08:54:21 -07:00
ArcDelay delay(*value);
if (!is_incremental_only_ && in_incremental_)
2026-03-13 14:06:35 -07:00
delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value, this);
else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) {
2018-09-28 08:54:21 -07:00
ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index);
2020-07-11 17:43:30 -07:00
if (delayGreater(prev_value, delay, min_max, this))
2026-01-03 16:59:35 -08:00
delay = prev_value;
2018-09-28 08:54:21 -07:00
}
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
graph_->setArcDelayAnnotated(edge, arc, arc_delay_index, true);
2018-09-28 08:54:21 -07:00
edge->setDelayAnnotationIsIncremental(is_incremental_only_);
}
}
bool
2026-03-28 19:13:35 -07:00
SdfReader::condMatch(std::string_view sdf_cond,
std::string_view lib_cond)
2018-09-28 08:54:21 -07:00
{
// If the sdf is not conditional it matches any library condition.
2026-03-28 19:13:35 -07:00
if (sdf_cond.empty())
2018-09-28 08:54:21 -07:00
return true;
2026-03-28 19:13:35 -07:00
else if (!sdf_cond.empty() && !lib_cond.empty()) {
2018-09-28 08:54:21 -07:00
// Match sdf_cond and lib_cond ignoring blanks.
2026-03-28 19:13:35 -07:00
size_t c1 = 0;
size_t c2 = 0;
while (c1 < sdf_cond.size()
&& c2 < lib_cond.size()) {
char ch1 = sdf_cond[c1++];
char ch2 = lib_cond[c2++];
while (c1 < sdf_cond.size()
&& isspace(ch1))
ch1 = sdf_cond[c1++];
while (c2 < lib_cond.size()
&& isspace(ch2))
ch2 = lib_cond[c2++];
2018-09-28 08:54:21 -07:00
if (ch1 != ch2)
2026-01-03 16:59:35 -08:00
return false;
2026-03-28 19:13:35 -07:00
}
return c1 == sdf_cond.size()
&& c2 == lib_cond.size();
2018-09-28 08:54:21 -07:00
}
else
return false;
}
SdfPortSpec *
2025-03-30 15:27:53 -07:00
SdfReader::makePortSpec(const Transition *tr,
2026-03-28 19:13:35 -07:00
std::string_view port)
{
return new SdfPortSpec(tr, port, "");
}
SdfPortSpec *
SdfReader::makePortSpec(const Transition *tr,
std::string_view port,
std::string_view cond)
2018-09-28 08:54:21 -07:00
{
2025-01-25 11:34:04 -07:00
return new SdfPortSpec(tr, port, cond);
2018-09-28 08:54:21 -07:00
}
SdfPortSpec *
2026-03-28 19:13:35 -07:00
SdfReader::makeCondPortSpec(std::string_view cond_port)
2018-09-28 08:54:21 -07:00
{
// Search from end to find port name because condition may contain spaces.
2026-03-28 19:13:35 -07:00
std::string cond_port1(cond_port);
2022-01-13 11:49:01 -07:00
trimRight(cond_port1);
2026-04-15 09:38:10 -07:00
auto port_idx = cond_port1.find_last_of(' ');
if (port_idx != std::string::npos) {
2026-03-28 19:13:35 -07:00
std::string port1 = cond_port1.substr(port_idx + 1);
2026-04-15 09:38:10 -07:00
size_t cond_end = cond_port1.find_last_not_of(' ', port_idx);
if (cond_end != std::string::npos) {
2026-03-28 19:13:35 -07:00
std::string cond1 = cond_port1.substr(0, cond_end + 1);
return new SdfPortSpec(Transition::riseFall(), port1, cond1);
2022-01-13 11:49:01 -07:00
}
}
return nullptr;
2018-09-28 08:54:21 -07:00
}
SdfTripleSeq *
SdfReader::makeTripleSeq()
{
return new SdfTripleSeq;
}
void
SdfReader::deleteTripleSeq(SdfTripleSeq *triples)
{
2026-01-03 16:59:35 -08:00
deleteContents(triples);
2018-09-28 08:54:21 -07:00
delete triples;
}
SdfTriple *
SdfReader::makeTriple()
{
2026-04-15 09:38:10 -07:00
return new SdfTriple(nullptr, nullptr, nullptr);
2018-09-28 08:54:21 -07:00
}
SdfTriple *
SdfReader::makeTriple(float value)
{
value *= timescale_;
float *fp = new float(value);
return new SdfTriple(fp, fp, fp);
}
SdfTriple *
SdfReader::makeTriple(float *min,
2026-01-03 16:59:35 -08:00
float *typ,
float *max)
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
if (min)
*min *= timescale_;
if (typ)
*typ *= timescale_;
if (max)
*max *= timescale_;
2018-09-28 08:54:21 -07:00
return new SdfTriple(min, typ, max);
}
void
SdfReader::deleteTriple(SdfTriple *triple)
{
delete triple;
}
void
SdfReader::setInTimingCheck(bool in)
{
in_timing_check_ = in;
}
void
SdfReader::setInIncremental(bool incr)
{
in_incremental_ = incr;
}
2026-03-28 19:13:35 -07:00
std::string
SdfReader::unescaped(std::string_view token)
2018-09-28 08:54:21 -07:00
{
char path_escape = network_->pathEscape();
char path_divider = network_->pathDivider();
2026-03-28 19:13:35 -07:00
size_t token_length = token.size();
std::string result;
2023-02-18 17:20:40 -07:00
for (size_t i = 0; i < token_length; i++) {
2026-03-28 19:13:35 -07:00
char ch = token[i];
2018-09-28 08:54:21 -07:00
if (ch == escape_) {
2026-03-28 19:13:35 -07:00
char next_ch = token[i + 1];
2018-09-28 08:54:21 -07:00
if (next_ch == divider_) {
2023-02-18 17:20:40 -07:00
// Escaped divider.
2026-01-03 16:59:35 -08:00
// Translate sdf escape to network escape.
2026-03-28 19:13:35 -07:00
result += path_escape;
2026-01-03 16:59:35 -08:00
// Translate sdf divider to network divider.
2026-03-28 19:13:35 -07:00
result += path_divider;
2018-09-28 08:54:21 -07:00
}
2026-03-15 14:35:24 -07:00
else if (next_ch == '[' || next_ch == ']' || next_ch == escape_) {
2026-01-03 16:59:35 -08:00
// Escaped bus bracket or escape.
// Translate sdf escape to network escape.
2026-03-28 19:13:35 -07:00
result += path_escape;
result += next_ch;
2018-09-28 08:54:21 -07:00
}
else
2023-02-18 17:20:40 -07:00
// Escaped non-divider character.
2026-03-28 19:13:35 -07:00
result += next_ch;
2023-02-18 17:20:40 -07:00
i++;
2018-09-28 08:54:21 -07:00
}
else
// Just the normal noises.
2026-03-28 19:13:35 -07:00
result += ch;
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
debugPrint(debug_, "sdf_name", 1, "unescape {} -> {}", token,
result);
return result;
2018-09-28 08:54:21 -07:00
}
2026-03-28 19:13:35 -07:00
std::string
SdfReader::makePath(std::string_view head,
std::string_view tail)
2023-02-18 17:20:40 -07:00
{
2026-03-28 19:13:35 -07:00
std::string path(head);
path += network_->pathDivider();
path += tail;
2023-02-18 17:20:40 -07:00
return path;
}
2026-03-28 19:13:35 -07:00
std::string
SdfReader::makeBusName(std::string_view base_name,
2025-01-25 11:34:04 -07:00
int index)
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
std::string bus_name = unescaped(base_name);
bus_name += '[';
bus_name += std::to_string(index);
bus_name += ']';
2025-01-25 11:34:04 -07:00
return bus_name;
2018-09-28 08:54:21 -07:00
}
2026-03-15 14:35:24 -07:00
int
SdfReader::sdfLine() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:35:24 -07:00
return scanner_->lineno();
2018-09-28 08:54:21 -07:00
}
Pin *
2026-03-28 19:13:35 -07:00
SdfReader::findPin(std::string_view name)
2018-09-28 08:54:21 -07:00
{
2026-03-28 19:13:35 -07:00
if (!path_.empty()) {
2026-03-02 12:13:13 -08:00
std::string path_name(path_);
2024-08-16 17:09:58 -07:00
path_name += divider_;
2026-03-28 19:13:35 -07:00
path_name += name;
Pin *pin = network_->findPin(path_name);
2019-01-16 15:37:31 -08:00
return pin;
}
else
2026-03-28 19:13:35 -07:00
return network_->findPin(name);
2018-09-28 08:54:21 -07:00
}
Instance *
2026-03-28 19:13:35 -07:00
SdfReader::findInstance(std::string_view name)
2018-09-28 08:54:21 -07:00
{
2026-03-02 12:13:13 -08:00
std::string inst_name;
2026-03-28 19:13:35 -07:00
if (!path_.empty()) {
2024-08-16 17:09:58 -07:00
inst_name = path_;
inst_name += divider_;
2026-03-28 19:13:35 -07:00
inst_name += name;
2024-08-16 17:09:58 -07:00
}
else
2026-03-28 19:13:35 -07:00
inst_name = name;
Instance *inst = network_->findInstance(inst_name);
2019-03-12 17:25:53 -07:00
if (inst == nullptr)
2026-03-15 14:35:24 -07:00
warn(195, "instance {} not found.", inst_name);
2018-09-28 08:54:21 -07:00
return inst;
}
////////////////////////////////////////////////////////////////
2025-01-25 11:34:04 -07:00
SdfPortSpec::SdfPortSpec(const Transition *tr,
2026-03-28 19:13:35 -07:00
std::string_view port,
std::string_view cond) :
2023-02-18 17:20:40 -07:00
tr_(tr),
2025-01-25 11:34:04 -07:00
port_(port),
cond_(cond)
2023-02-18 17:20:40 -07:00
{
}
////////////////////////////////////////////////////////////////
2018-09-28 08:54:21 -07:00
SdfTriple::SdfTriple(float *min,
2026-01-03 16:59:35 -08:00
float *typ,
float *max)
2018-09-28 08:54:21 -07:00
{
values_[0] = min;
values_[1] = typ;
values_[2] = max;
}
SdfTriple::~SdfTriple()
{
if (values_[0] == values_[1] && values_[0] == values_[2])
delete values_[0];
else {
2026-03-15 14:35:24 -07:00
if (values_[0])
delete values_[0];
if (values_[1])
delete values_[1];
if (values_[2])
delete values_[2];
2018-09-28 08:54:21 -07:00
}
}
bool
SdfTriple::hasValue() const
{
return values_[0] || values_[1] || values_[2];
}
2025-01-25 11:34:04 -07:00
////////////////////////////////////////////////////////////////
2018-09-28 08:54:21 -07:00
2025-01-25 11:34:04 -07:00
SdfScanner::SdfScanner(std::istream *stream,
2026-03-28 19:13:35 -07:00
std::string_view filename,
2025-01-25 11:34:04 -07:00
SdfReader *reader,
Report *report) :
yyFlexLexer(stream),
filename_(filename),
reader_(reader),
report_(report)
{
}
2018-09-28 08:54:21 -07:00
2025-01-25 11:34:04 -07:00
void
2026-03-28 19:13:35 -07:00
SdfScanner::error(std::string_view msg)
2025-01-25 11:34:04 -07:00
{
2026-03-28 19:13:35 -07:00
report_->fileError(196, filename_, lineno(), "{}", msg);
2025-01-25 11:34:04 -07:00
}
2026-03-15 14:35:24 -07:00
} // namespace sta