2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, Parallax Software, Inc.
|
2018-09-28 17:54:21 +02:00
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2022-01-04 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01: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 17:54:21 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "SpefReader.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Zlib.hh"
|
2024-11-20 22:11:10 +01:00
|
|
|
#include "Stats.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Debug.hh"
|
|
|
|
|
#include "StringUtil.hh"
|
|
|
|
|
#include "Map.hh"
|
|
|
|
|
#include "Transition.hh"
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "PortDirection.hh"
|
|
|
|
|
#include "Sdc.hh"
|
|
|
|
|
#include "Parasitics.hh"
|
2024-02-08 21:54:52 +01:00
|
|
|
#include "Corner.hh"
|
|
|
|
|
#include "ArcDelayCalc.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "SpefReaderPvt.hh"
|
|
|
|
|
#include "SpefNamespace.hh"
|
2025-02-01 23:49:30 +01:00
|
|
|
#include "parasitics/SpefScanner.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2025-05-22 18:25:56 +02:00
|
|
|
using std::string;
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
bool
|
|
|
|
|
readSpefFile(const char *filename,
|
|
|
|
|
Instance *instance,
|
|
|
|
|
ParasiticAnalysisPt *ap,
|
2018-11-26 18:15:52 +01:00
|
|
|
bool pin_cap_included,
|
2018-09-28 17:54:21 +02:00
|
|
|
bool keep_coupling_caps,
|
|
|
|
|
float coupling_cap_factor,
|
2024-02-08 21:54:52 +01:00
|
|
|
bool reduce,
|
2018-09-28 17:54:21 +02:00
|
|
|
const Corner *corner,
|
2024-02-08 21:54:52 +01:00
|
|
|
const MinMaxAll *min_max,
|
|
|
|
|
StaState *sta)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-02-01 23:49:30 +01:00
|
|
|
SpefReader reader(filename, instance, ap,
|
|
|
|
|
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
|
|
|
|
|
reduce, corner, min_max, sta);
|
|
|
|
|
bool success = reader.read();
|
2018-09-28 17:54:21 +02:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SpefReader::SpefReader(const char *filename,
|
|
|
|
|
Instance *instance,
|
|
|
|
|
ParasiticAnalysisPt *ap,
|
2018-11-26 18:15:52 +01:00
|
|
|
bool pin_cap_included,
|
2018-09-28 17:54:21 +02:00
|
|
|
bool keep_coupling_caps,
|
|
|
|
|
float coupling_cap_factor,
|
2024-02-08 21:54:52 +01:00
|
|
|
bool reduce,
|
2018-09-28 17:54:21 +02:00
|
|
|
const Corner *corner,
|
2024-02-08 21:54:52 +01:00
|
|
|
const MinMaxAll *min_max,
|
|
|
|
|
StaState *sta) :
|
|
|
|
|
StaState(sta),
|
2019-01-17 00:37:31 +01:00
|
|
|
filename_(filename),
|
|
|
|
|
instance_(instance),
|
|
|
|
|
ap_(ap),
|
|
|
|
|
pin_cap_included_(pin_cap_included),
|
|
|
|
|
keep_coupling_caps_(keep_coupling_caps),
|
2024-02-08 21:54:52 +01:00
|
|
|
reduce_(reduce),
|
2019-01-17 00:37:31 +01:00
|
|
|
corner_(corner),
|
2024-02-08 21:54:52 +01:00
|
|
|
min_max_(min_max),
|
2019-01-17 00:37:31 +01:00
|
|
|
// defaults
|
|
|
|
|
divider_('\0'),
|
|
|
|
|
delimiter_('\0'),
|
|
|
|
|
bus_brkt_left_('\0'),
|
|
|
|
|
bus_brkt_right_('\0'),
|
2019-03-13 01:25:53 +01:00
|
|
|
net_(nullptr),
|
2018-09-28 17:54:21 +02:00
|
|
|
triple_index_(0),
|
2022-10-19 17:49:22 +02:00
|
|
|
time_scale_(1.0),
|
|
|
|
|
cap_scale_(1.0),
|
|
|
|
|
res_scale_(1.0),
|
|
|
|
|
induct_scale_(1.0),
|
2019-03-13 01:25:53 +01:00
|
|
|
design_flow_(nullptr),
|
|
|
|
|
parasitic_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-01-17 00:37:31 +01:00
|
|
|
ap->setCouplingCapFactor(coupling_cap_factor);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SpefReader::~SpefReader()
|
|
|
|
|
{
|
|
|
|
|
if (design_flow_) {
|
|
|
|
|
deleteContents(design_flow_);
|
|
|
|
|
delete design_flow_;
|
2019-03-13 01:25:53 +01:00
|
|
|
design_flow_ = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-01 23:49:30 +01:00
|
|
|
bool
|
|
|
|
|
SpefReader::read()
|
|
|
|
|
{
|
|
|
|
|
bool success;
|
|
|
|
|
gzstream::igzstream stream(filename_);
|
|
|
|
|
if (stream.is_open()) {
|
|
|
|
|
Stats stats(debug_, report_);
|
|
|
|
|
SpefScanner scanner(&stream, filename_, this, report_);
|
|
|
|
|
scanner_ = &scanner;
|
|
|
|
|
SpefParse parser(&scanner, this);
|
2025-02-11 01:32:50 +01:00
|
|
|
//parser.set_debug_level(1);
|
2025-02-01 23:49:30 +01:00
|
|
|
// yyparse returns 0 on success.
|
|
|
|
|
success = (parser.parse() == 0);
|
|
|
|
|
stats.report("Read spef");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw FileNotReadable(filename_);
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-17 00:37:31 +01:00
|
|
|
void
|
|
|
|
|
SpefReader::setDivider(char divider)
|
|
|
|
|
{
|
|
|
|
|
divider_ = divider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setDelimiter(char delimiter)
|
|
|
|
|
{
|
|
|
|
|
delimiter_ = delimiter;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
void
|
2025-02-01 23:49:30 +01:00
|
|
|
SpefReader::setBusBrackets(char left,
|
|
|
|
|
char right)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (!((left == '[' && right == ']')
|
|
|
|
|
|| (left == '{' && right == '}')
|
|
|
|
|
|| (left == '(' && right == ')')
|
|
|
|
|
|| (left == '<' && right == '>')
|
|
|
|
|
|| (left == ':' && right == '\0')
|
|
|
|
|
|| (left == '.' && right == '\0')))
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1640, "illegal bus delimiters.");
|
2019-01-17 00:37:31 +01:00
|
|
|
bus_brkt_left_ = left;
|
|
|
|
|
bus_brkt_right_ = right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Instance *
|
|
|
|
|
SpefReader::findInstanceRelative(const char *name)
|
|
|
|
|
{
|
2025-02-11 01:32:50 +01:00
|
|
|
return sdc_network_->findInstanceRelative(instance_, name);
|
2019-01-17 00:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Net *
|
|
|
|
|
SpefReader::findNetRelative(const char *name)
|
|
|
|
|
{
|
2024-12-23 01:11:21 +01:00
|
|
|
Net *net = network_->findNetRelative(instance_, name);
|
|
|
|
|
// Relax spef escaping requirement because some commercial tools
|
|
|
|
|
// don't follow the rules.
|
|
|
|
|
if (net == nullptr)
|
|
|
|
|
net = sdc_network_->findNetRelative(instance_, name);
|
|
|
|
|
return net;
|
2019-01-17 00:37:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pin *
|
|
|
|
|
SpefReader::findPinRelative(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return network_->findPinRelative(instance_, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pin *
|
|
|
|
|
SpefReader::findPortPinRelative(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return network_->findPin(instance_, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
SpefReader::translated(const char *token)
|
|
|
|
|
{
|
|
|
|
|
return spefToSta(token, divider_, network_->pathDivider(),
|
|
|
|
|
network_->pathEscape());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-14 02:21:35 +01:00
|
|
|
SpefReader::warn(int id, const char *fmt, ...)
|
2019-01-17 00:37:31 +01:00
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
2025-02-01 23:49:30 +01:00
|
|
|
report_->vfileWarn(id, filename_, scanner_->line(), fmt, args);
|
2019-01-17 00:37:31 +01:00
|
|
|
va_end(args);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setTimeScale(float scale,
|
|
|
|
|
const char *units)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(units, "NS"))
|
|
|
|
|
time_scale_ = scale * 1E-9F;
|
|
|
|
|
else if (stringEq(units, "PS"))
|
|
|
|
|
time_scale_ = scale * 1E-12F;
|
|
|
|
|
else
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1641, "unknown units %s.", units);
|
2018-09-28 17:54:21 +02:00
|
|
|
stringDelete(units);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setCapScale(float scale,
|
|
|
|
|
const char *units)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(units, "PF"))
|
|
|
|
|
cap_scale_ = scale * 1E-12F;
|
|
|
|
|
else if (stringEq(units, "FF"))
|
|
|
|
|
cap_scale_ = scale * 1E-15F;
|
|
|
|
|
else
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1642, "unknown units %s.", units);
|
2018-09-28 17:54:21 +02:00
|
|
|
stringDelete(units);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setResScale(float scale,
|
|
|
|
|
const char *units)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(units, "OHM"))
|
|
|
|
|
res_scale_ = scale;
|
|
|
|
|
else if (stringEq(units, "KOHM"))
|
|
|
|
|
res_scale_ = scale * 1E+3F;
|
|
|
|
|
else
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1643, "unknown units %s.", units);
|
2018-09-28 17:54:21 +02:00
|
|
|
stringDelete(units);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setInductScale(float scale,
|
|
|
|
|
const char *units)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(units, "HENRY"))
|
|
|
|
|
induct_scale_ = scale;
|
|
|
|
|
else if (stringEq(units, "MH"))
|
|
|
|
|
induct_scale_ = scale * 1E-3F;
|
|
|
|
|
else if (stringEq(units, "UH"))
|
|
|
|
|
induct_scale_ = scale * 1E-6F;
|
|
|
|
|
else
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1644, "unknown units %s.", units);
|
2018-09-28 17:54:21 +02:00
|
|
|
stringDelete(units);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-11 01:32:50 +01:00
|
|
|
SpefReader::makeNameMapEntry(const char *index,
|
|
|
|
|
const char *name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
int i = atoi(index + 1);
|
|
|
|
|
name_map_[i] = name;
|
2025-02-11 23:33:59 +01:00
|
|
|
stringDelete(index);
|
|
|
|
|
stringDelete(name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-02-11 01:32:50 +01:00
|
|
|
const char *
|
|
|
|
|
SpefReader::nameMapLookup(const char *name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (name && name[0] == '*') {
|
|
|
|
|
int index = atoi(name + 1);
|
2025-02-11 01:32:50 +01:00
|
|
|
const auto &itr = name_map_.find(index);
|
2024-02-08 21:54:52 +01:00
|
|
|
if (itr != name_map_.end())
|
2025-02-11 01:32:50 +01:00
|
|
|
return itr->second.c_str();
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1645, "no name map entry for %d.", index);
|
2022-01-15 20:51:05 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PortDirection *
|
|
|
|
|
SpefReader::portDirection(char *spef_dir)
|
|
|
|
|
{
|
|
|
|
|
PortDirection *direction = PortDirection::unknown();
|
|
|
|
|
if (stringEq(spef_dir, "I"))
|
|
|
|
|
direction = PortDirection::input();
|
|
|
|
|
else if (stringEq(spef_dir, "O"))
|
|
|
|
|
direction = PortDirection::output();
|
|
|
|
|
else if (stringEq(spef_dir, "B"))
|
|
|
|
|
direction = PortDirection::bidirect();
|
|
|
|
|
else
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1646, "unknown port direction %s.", spef_dir);
|
2018-09-28 17:54:21 +02:00
|
|
|
return direction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::setDesignFlow(StringSeq *flow)
|
|
|
|
|
{
|
|
|
|
|
design_flow_ = flow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pin *
|
|
|
|
|
SpefReader::findPin(char *name)
|
|
|
|
|
{
|
2019-04-11 05:36:48 +02:00
|
|
|
Pin *pin = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (name) {
|
|
|
|
|
char *delim = strrchr(name, delimiter_);
|
|
|
|
|
if (delim) {
|
|
|
|
|
*delim = '\0';
|
2025-02-11 01:32:50 +01:00
|
|
|
const char *name1 = nameMapLookup(name);
|
|
|
|
|
if (name1) {
|
|
|
|
|
Instance *inst = findInstanceRelative(name1);
|
2022-01-15 20:51:05 +01:00
|
|
|
// Replace delimiter for error messages.
|
|
|
|
|
*delim = delimiter_;
|
|
|
|
|
const char *port_name = delim + 1;
|
|
|
|
|
if (inst) {
|
|
|
|
|
pin = network_->findPin(inst, port_name);
|
|
|
|
|
if (pin == nullptr)
|
2025-02-11 01:32:50 +01:00
|
|
|
warn(1647, "pin %s not found.", name1);
|
2022-01-15 20:51:05 +01:00
|
|
|
}
|
|
|
|
|
else
|
2025-02-11 01:32:50 +01:00
|
|
|
warn(1648, "instance %s not found.", name1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
pin = findPortPinRelative(name);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (pin == nullptr)
|
2024-02-08 21:54:52 +01:00
|
|
|
warn(1649, "pin %s not found.", name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return pin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Net *
|
2025-02-11 01:32:50 +01:00
|
|
|
SpefReader::findNet(const char *name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-04-11 05:36:48 +02:00
|
|
|
Net *net = nullptr;
|
2025-02-11 01:32:50 +01:00
|
|
|
const char *name1 = nameMapLookup(name);
|
|
|
|
|
if (name1) {
|
|
|
|
|
net = findNetRelative(name1);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (net == nullptr)
|
2025-02-11 01:32:50 +01:00
|
|
|
warn(1650, "net %s not found.", name1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::rspfBegin(Net *net,
|
|
|
|
|
SpefTriple *total_cap)
|
|
|
|
|
{
|
2022-10-06 06:46:05 +02:00
|
|
|
if (net)
|
2018-09-28 17:54:21 +02:00
|
|
|
parasitics_->deleteParasitics(net, ap_);
|
|
|
|
|
// Net total capacitance is ignored.
|
|
|
|
|
delete total_cap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::rspfFinish()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::rspfDrvrBegin(Pin *drvr_pin,
|
|
|
|
|
SpefRspfPi *pi)
|
|
|
|
|
{
|
|
|
|
|
if (drvr_pin) {
|
2022-10-06 06:46:05 +02:00
|
|
|
float c2 = pi->c2()->value(triple_index_) * cap_scale_;
|
|
|
|
|
float rpi = pi->r1()->value(triple_index_) * res_scale_;
|
|
|
|
|
float c1 = pi->c1()->value(triple_index_) * cap_scale_;
|
|
|
|
|
// Only one parasitic, save it under rise transition.
|
2024-02-08 21:54:52 +01:00
|
|
|
parasitic_ = parasitics_->makePiElmore(drvr_pin, RiseFall::rise(), ap_,
|
|
|
|
|
c2, rpi, c1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
delete pi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::rspfLoad(Pin *load_pin,
|
|
|
|
|
SpefTriple *rc)
|
|
|
|
|
{
|
|
|
|
|
if (parasitic_ && load_pin) {
|
|
|
|
|
float elmore = rc->value(triple_index_) * time_scale_;
|
|
|
|
|
parasitics_->setElmore(parasitic_, load_pin, elmore);
|
|
|
|
|
}
|
|
|
|
|
delete rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::rspfDrvrFinish()
|
|
|
|
|
{
|
2019-04-11 05:36:48 +02:00
|
|
|
parasitic_ = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Net cap (total_cap) is ignored.
|
|
|
|
|
void
|
|
|
|
|
SpefReader::dspfBegin(Net *net,
|
|
|
|
|
SpefTriple *total_cap)
|
|
|
|
|
{
|
|
|
|
|
if (net) {
|
2022-10-06 06:46:05 +02:00
|
|
|
if (network_->isTopInstance(instance_)) {
|
|
|
|
|
parasitics_->deleteReducedParasitics(net, ap_);
|
|
|
|
|
parasitic_ = parasitics_->makeParasiticNetwork(net, pin_cap_included_, ap_);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Net *parasitic_owner = net;
|
2022-10-03 18:06:41 +02:00
|
|
|
NetTermIterator *term_iter = network_->termIterator(net);
|
|
|
|
|
if (term_iter->hasNext()) {
|
|
|
|
|
Term *term = term_iter->next();
|
|
|
|
|
Pin *hpin = network_->pin(term);
|
|
|
|
|
parasitic_owner = network_->net(hpin);
|
|
|
|
|
}
|
|
|
|
|
delete term_iter;
|
|
|
|
|
parasitic_ = parasitics_->findParasiticNetwork(parasitic_owner, ap_);
|
2022-10-06 06:46:05 +02:00
|
|
|
if (parasitic_ == nullptr)
|
2022-10-03 18:06:41 +02:00
|
|
|
parasitic_ = parasitics_->makeParasiticNetwork(parasitic_owner,
|
|
|
|
|
pin_cap_included_, ap_);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
net_ = net;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-04-11 05:36:48 +02:00
|
|
|
parasitic_ = nullptr;
|
|
|
|
|
net_ = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
delete total_cap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::dspfFinish()
|
|
|
|
|
{
|
2024-02-08 21:54:52 +01:00
|
|
|
if (parasitic_ && reduce_) {
|
|
|
|
|
arc_delay_calc_->reduceParasitic(parasitic_, net_, corner_, min_max_);
|
|
|
|
|
parasitics_->deleteParasiticNetwork(net_, ap_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-04-11 05:36:48 +02:00
|
|
|
parasitic_ = nullptr;
|
|
|
|
|
net_ = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ParasiticNode *
|
|
|
|
|
SpefReader::findParasiticNode(char *name,
|
2024-02-08 21:54:52 +01:00
|
|
|
bool local_only)
|
|
|
|
|
{
|
2024-01-15 02:22:48 +01:00
|
|
|
if (name && parasitic_) {
|
|
|
|
|
char *delim = strrchr(name, delimiter_);
|
|
|
|
|
if (delim) {
|
|
|
|
|
*delim = '\0';
|
|
|
|
|
char *name2 = delim + 1;
|
2025-02-11 01:32:50 +01:00
|
|
|
const char *name1 = nameMapLookup(name);
|
|
|
|
|
if (name1) {
|
|
|
|
|
Instance *inst = findInstanceRelative(name1);
|
2024-02-27 18:00:48 +01:00
|
|
|
if (inst) {
|
|
|
|
|
// <instance>:<port>
|
|
|
|
|
Pin *pin = network_->findPin(inst, name2);
|
|
|
|
|
if (pin) {
|
|
|
|
|
if (local_only
|
|
|
|
|
&& !network_->isConnected(net_, pin))
|
2025-10-15 00:58:48 +02:00
|
|
|
warn(1651, "%s not connected to net %s.",
|
|
|
|
|
name1, sdc_network_->pathName(net_));
|
2024-02-27 18:00:48 +01:00
|
|
|
return parasitics_->ensureParasiticNode(parasitic_, pin, network_);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Replace delimiter for error message.
|
|
|
|
|
*delim = delimiter_;
|
2025-02-11 01:32:50 +01:00
|
|
|
warn(1652, "pin %s not found.", name1);
|
2024-02-27 18:00:48 +01:00
|
|
|
}
|
2024-01-15 02:22:48 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2025-02-11 01:32:50 +01:00
|
|
|
Net *net = findNet(name1);
|
2024-02-27 18:00:48 +01:00
|
|
|
// Replace delimiter for error messages.
|
2024-01-15 02:22:48 +01:00
|
|
|
*delim = delimiter_;
|
2024-02-27 18:00:48 +01:00
|
|
|
if (net) {
|
|
|
|
|
// <net>:<subnode_id>
|
|
|
|
|
const char *id_str = delim + 1;
|
|
|
|
|
if (isDigits(id_str)) {
|
|
|
|
|
int id = atoi(id_str);
|
|
|
|
|
if (local_only
|
|
|
|
|
&& !network_->isConnected(net, net_))
|
2024-06-27 22:57:58 +02:00
|
|
|
warn(1653, "%s not connected to net %s.",
|
2025-02-11 01:32:50 +01:00
|
|
|
name1,
|
2024-06-27 22:57:58 +02:00
|
|
|
network_->pathName(net_));
|
2024-02-27 18:00:48 +01:00
|
|
|
return parasitics_->ensureParasiticNode(parasitic_, net, id, network_);
|
|
|
|
|
}
|
|
|
|
|
else
|
2025-02-11 01:32:50 +01:00
|
|
|
warn(1654, "node %s not a pin or net:number", name1);
|
2024-01-15 02:22:48 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// <top_level_port>
|
2025-02-11 01:32:50 +01:00
|
|
|
const char *name1 = nameMapLookup(name);
|
|
|
|
|
if (name1) {
|
|
|
|
|
Pin *pin = findPortPinRelative(name1);
|
|
|
|
|
if (pin) {
|
|
|
|
|
if (local_only
|
|
|
|
|
&& !network_->isConnected(net_, pin))
|
|
|
|
|
warn(1655, "%s not connected to net %s.", name1, network_->pathName(net_));
|
|
|
|
|
return parasitics_->ensureParasiticNode(parasitic_, pin, network_);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
warn(1656, "pin %s not found.", name1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2024-01-15 02:22:48 +01:00
|
|
|
else
|
2025-02-12 19:20:05 +01:00
|
|
|
warn(1657, "pin %s not found.", name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-08 21:54:52 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::makeCapacitor(int, char *node_name,
|
|
|
|
|
SpefTriple *cap)
|
|
|
|
|
{
|
2024-02-08 21:54:52 +01:00
|
|
|
ParasiticNode *node = findParasiticNode(node_name, true);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (node) {
|
|
|
|
|
float cap1 = cap->value(triple_index_) * cap_scale_;
|
2024-02-08 21:54:52 +01:00
|
|
|
parasitics_->incrCap(node, cap1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
delete cap;
|
|
|
|
|
stringDelete(node_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::makeCapacitor(int id,
|
|
|
|
|
char *node_name1,
|
|
|
|
|
char *node_name2,
|
|
|
|
|
SpefTriple *cap)
|
|
|
|
|
{
|
2024-02-08 21:54:52 +01:00
|
|
|
ParasiticNode *node1 = findParasiticNode(node_name1, false);
|
|
|
|
|
ParasiticNode *node2 = findParasiticNode(node_name2, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
float cap1 = cap->value(triple_index_) * cap_scale_;
|
2024-02-08 21:54:52 +01:00
|
|
|
if (cap1 > 0.0) {
|
|
|
|
|
if (keep_coupling_caps_)
|
|
|
|
|
parasitics_->makeCapacitor(parasitic_, id, cap1, node1, node2);
|
|
|
|
|
else {
|
|
|
|
|
float scaled_cap = cap1 * ap_->couplingCapFactor();
|
|
|
|
|
if (node1 && parasitics_->net(node1, network_) == net_)
|
|
|
|
|
parasitics_->incrCap(node1, scaled_cap);
|
|
|
|
|
if (node2 && parasitics_->net(node2, network_) == net_)
|
|
|
|
|
parasitics_->incrCap(node2, scaled_cap);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
delete cap;
|
|
|
|
|
stringDelete(node_name1);
|
|
|
|
|
stringDelete(node_name2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SpefReader::makeResistor(int id,
|
|
|
|
|
char *node_name1,
|
|
|
|
|
char *node_name2,
|
|
|
|
|
SpefTriple *res)
|
|
|
|
|
{
|
2024-02-08 21:54:52 +01:00
|
|
|
ParasiticNode *node1 = findParasiticNode(node_name1, true);
|
|
|
|
|
ParasiticNode *node2 = findParasiticNode(node_name2, true);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (node1 && node2) {
|
|
|
|
|
float res1 = res->value(triple_index_) * res_scale_;
|
2024-02-08 21:54:52 +01:00
|
|
|
parasitics_->makeResistor(parasitic_, id, res1, node1, node2);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
delete res;
|
|
|
|
|
stringDelete(node_name1);
|
|
|
|
|
stringDelete(node_name2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
SpefRspfPi::SpefRspfPi(SpefTriple *c2,
|
|
|
|
|
SpefTriple *r1,
|
|
|
|
|
SpefTriple *c1) :
|
|
|
|
|
c2_(c2),
|
|
|
|
|
r1_(r1),
|
|
|
|
|
c1_(c1)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SpefRspfPi::~SpefRspfPi()
|
|
|
|
|
{
|
|
|
|
|
delete c2_;
|
|
|
|
|
delete r1_;
|
|
|
|
|
delete c1_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
SpefTriple::SpefTriple(float value) :
|
|
|
|
|
is_triple_(false)
|
|
|
|
|
{
|
|
|
|
|
values_[0] = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SpefTriple::SpefTriple(float value1,
|
|
|
|
|
float value2,
|
|
|
|
|
float value3) :
|
|
|
|
|
is_triple_(true)
|
|
|
|
|
{
|
|
|
|
|
values_[0] = value1;
|
|
|
|
|
values_[1] = value2;
|
|
|
|
|
values_[2] = value3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
SpefTriple::value(int index) const
|
|
|
|
|
{
|
|
|
|
|
if (is_triple_)
|
|
|
|
|
return values_[index];
|
|
|
|
|
else
|
|
|
|
|
return values_[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-02-01 23:49:30 +01:00
|
|
|
SpefScanner::SpefScanner(std::istream *stream,
|
|
|
|
|
const string &filename,
|
|
|
|
|
SpefReader *reader,
|
|
|
|
|
Report *report) :
|
|
|
|
|
yyFlexLexer(stream),
|
|
|
|
|
filename_(filename),
|
|
|
|
|
reader_(reader),
|
|
|
|
|
report_(report)
|
|
|
|
|
{
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-02-01 23:49:30 +01:00
|
|
|
void
|
|
|
|
|
SpefScanner::error(const char *msg)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-02-12 18:33:13 +01:00
|
|
|
report_->fileError(1867, filename_.c_str(), lineno(), "%s", msg);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-02-01 23:49:30 +01:00
|
|
|
|
|
|
|
|
} // namespace
|