// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// 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 .
//
// 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.
#pragma once
#include
#include
#include
#include "TimingRole.hh"
#include "Transition.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "Report.hh"
#include "SdcClass.hh"
#include "StaState.hh"
namespace sta {
class Report;
class SdfTriple;
class SdfPortSpec;
class SdfScanner;
using SdfTripleSeq = std::vector;
class SdfReader : public StaState
{
public:
SdfReader(std::string_view filename,
std::string_view path,
int arc_min_index,
int arc_max_index,
AnalysisType analysis_type,
bool unescaped_dividers,
bool is_incremental_only,
MinMaxAll *cond_use,
StaState *sta);
~SdfReader();
bool read();
void setDivider(char divider);
void setTimescale(float multiplier,
std::string_view units);
void setPortDeviceDelay(Edge *edge,
SdfTripleSeq *triples,
bool from_trans);
void setEdgeArcDelays(Edge *edge,
TimingArc *arc,
SdfTriple *triple);
void setEdgeArcDelays(Edge *edge,
TimingArc *arc,
SdfTriple *triple,
int triple_index,
int arc_delay_index);
void setEdgeArcDelaysCondUse(Edge *edge,
TimingArc *arc,
SdfTriple *triple);
void setEdgeArcDelaysCondUse(Edge *edge,
TimingArc *arc,
float *value,
int triple_index,
int arc_delay_index,
const MinMax *min_max);
void setInstance();
void setInstance(std::string_view instance_name);
void setInstanceWildcard();
void cellFinish();
void setCell(std::string_view cell_name);
void interconnect(std::string_view from_pin_name,
std::string_view to_pin_name,
SdfTripleSeq *triples);
void iopath(SdfPortSpec *from_edge,
std::string_view to_port_name,
SdfTripleSeq *triples,
std::string_view cond,
bool condelse);
void timingCheck(const TimingRole *role,
SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *triple);
void timingCheckWidth(SdfPortSpec *edge,
SdfTriple *triple);
void timingCheckPeriod(SdfPortSpec *edge,
SdfTriple *triple);
void timingCheckSetupHold(SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *setup_triple,
SdfTriple *hold_triple);
void timingCheckRecRem(SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *rec_triple,
SdfTriple *rem_triple);
void timingCheckSetupHold1(SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *setup_triple,
SdfTriple *hold_triple,
const TimingRole *setup_role,
const TimingRole *hold_role);
void timingCheckNochange(SdfPortSpec *data_edge,
SdfPortSpec *clk_edge,
SdfTriple *before_triple,
SdfTriple *after_triple);
void port(std::string_view o_pin_name,
SdfTripleSeq *triples);
void device(SdfTripleSeq *triples);
void device(std::string_view to_pin_name,
SdfTripleSeq *triples);
SdfTriple *makeTriple();
SdfTriple *makeTriple(float value);
SdfTriple *makeTriple(float *min,
float *typ,
float *max);
void deleteTriple(SdfTriple *triple);
SdfTripleSeq *makeTripleSeq();
void deleteTripleSeq(SdfTripleSeq *triples);
SdfPortSpec *makePortSpec(const Transition *tr,
std::string_view port);
SdfPortSpec *makePortSpec(const Transition *tr,
std::string_view port,
std::string_view cond);
SdfPortSpec *makeCondPortSpec(std::string_view cond_port);
std::string unescaped(std::string_view token);
std::string makePath(std::string_view head,
std::string_view tail);
// Parser state used to control lexer for COND handling.
bool inTimingCheck() { return in_timing_check_; }
void setInTimingCheck(bool in);
bool inIncremental() const { return in_incremental_; }
void setInIncremental(bool incr);
std::string makeBusName(std::string_view bus_name,
int index);
std::string_view filename() const { return filename_; }
int sdfLine() const;
template
void warn(int id,
std::string_view fmt,
Args &&...args)
{
report_->fileWarn(id, filename_, sdfLine(), fmt,
std::forward(args)...);
}
template
void error(int id,
std::string_view fmt,
Args &&...args)
{
report_->fileError(id, filename_, sdfLine(), fmt,
std::forward(args)...);
}
private:
Edge *findCheckEdge(Pin *from_pin,
Pin *to_pin,
const TimingRole *sdf_role,
const std::string *cond_start,
const std::string *cond_end);
Edge *findWireEdge(Pin *from_pin,
Pin *to_pin);
bool condMatch(std::string_view sdf_cond,
std::string_view lib_cond);
void timingCheck1(const TimingRole *role,
Port *data_port,
SdfPortSpec *data_edge,
Port *clk_port,
SdfPortSpec *clk_edge,
SdfTriple *triple);
bool annotateCheckEdges(Pin *data_pin,
SdfPortSpec *data_edge,
Pin *clk_pin,
SdfPortSpec *clk_edge,
const TimingRole *sdf_role,
SdfTriple *triple,
bool match_generic);
Pin *findPin(std::string_view name);
Instance *findInstance(std::string_view name);
void setEdgeDelays(Edge *edge,
SdfTripleSeq *triples,
std::string_view sdf_cmd);
void setDevicePinDelays(Pin *to_pin,
SdfTripleSeq *triples);
Port *findPort(const Cell *cell,
std::string_view port_name);
std::string_view filename_;
SdfScanner *scanner_;
std::string_view path_;
// Which values to pull out of the sdf triples.
int triple_min_index_;
int triple_max_index_;
// Which arc delay value to deposit the sdf values into.
int arc_delay_min_index_;
int arc_delay_max_index_;
AnalysisType analysis_type_;
bool unescaped_dividers_;
bool is_incremental_only_;
MinMaxAll *cond_use_;
char divider_;
char escape_;
Instance *instance_;
std::string cell_name_;
bool in_timing_check_;
bool in_incremental_;
float timescale_;
static const int null_index_ = -1;
};
} // namespace