OpenSTA/parasitics/SpfReader.cc

634 lines
14 KiB
C++

// OpenSTA, Static Timing Analyzer
// Copyright (c) 2019, 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 <https://www.gnu.org/licenses/>.
#include "Machine.hh"
#include "Zlib.hh"
#include "Debug.hh"
#include "StringUtil.hh"
#include "Map.hh"
#include "Network.hh"
#include "Transition.hh"
#include "Parasitics.hh"
#include "SpfReaderPvt.hh"
#include "SpfReader.hh"
int
SpfParse_parse();
void
spfResetScanner();
namespace sta {
SpfReader *spf_reader;
const Pin *SpfReader::gnd_net_ = reinterpret_cast<Pin*>(1);
const Pin *SpfReader::rspf_subnode_ = reinterpret_cast<Pin*>(2);
bool
readSpfFile(const char *filename,
gzFile stream,
int line,
bool rspf,
Instance *instance,
ParasiticAnalysisPt *ap,
bool increment,
bool pin_cap_included,
bool keep_coupling_caps,
float coupling_cap_factor,
ReduceParasiticsTo reduce_to,
bool delete_after_reduce,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *cnst_min_max,
bool save,
bool quiet,
Report *report,
Network *network,
Parasitics *parasitics)
{
SpfReader reader(filename, stream, line, rspf, instance, ap,
increment, pin_cap_included, keep_coupling_caps,
coupling_cap_factor, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, quiet,
report, network, parasitics);
spf_reader = &reader;
::spfResetScanner();
// yyparse returns 0 on success.
bool success = (::SpfParse_parse() == 0);
if (success && save)
parasitics->save();
return success;
}
SpfReader::SpfReader(const char *filename,
gzFile stream,
int line,
bool rspf,
Instance *instance,
ParasiticAnalysisPt *ap,
bool increment,
bool pin_cap_included,
bool keep_coupling_caps,
float coupling_cap_factor,
ReduceParasiticsTo reduce_to,
bool delete_after_reduce,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *cnst_min_max,
bool quiet,
Report *report,
Network *network,
Parasitics *parasitics):
SpfSpefReader(filename, stream, line, instance, ap, increment,
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
reduce_to, delete_after_reduce, op_cond, corner, cnst_min_max,
quiet, report, network, parasitics),
is_rspf_(rspf),
gnd_net_name_(NULL)
{
}
SpfReader::~SpfReader()
{
clearPinMap();
// gnd_net remains in the pin map, so delete it here.
if (gnd_net_name_)
stringDelete(gnd_net_name_);
pin_node_map_.clear();
}
void
SpfReader::setGroundNet(const char *ground_net)
{
gnd_net_name_ = ground_net;
pin_node_map_[ground_net] = gnd_net_;
}
// Some SPF writers use DRIVER/LOAD stmts to define an alias for the
// pin name so make a table to map from the name to the node/pin.
void
SpfReader::rspfDrvrBegin(const char *drvr_pin_name)
{
rspf_drvr_pin_ = findPinRelative(drvr_pin_name);
if (rspf_drvr_pin_)
pin_node_map_[drvr_pin_name] = rspf_drvr_pin_;
else {
pinNotFound(drvr_pin_name);
stringDelete(drvr_pin_name);
}
rspfDrvrBegin();
}
void
SpfReader::rspfDrvrBegin(const char *drvr_pin_name,
const char *inst_name,
const char *port_name)
{
rspf_drvr_pin_ = 0;
parasitic_ = 0;
Instance *inst = findInstanceRelative(inst_name);
if (inst) {
rspf_drvr_pin_ = network_->findPinRelative(inst, port_name);
if (rspf_drvr_pin_)
pin_node_map_[drvr_pin_name] = rspf_drvr_pin_;
else {
instPinNotFound(inst_name, port_name);
stringDelete(drvr_pin_name);
}
}
else {
instNotFound(inst_name);
stringDelete(drvr_pin_name);
}
rspfDrvrBegin();
stringDelete(inst_name);
stringDelete(port_name);
}
void
SpfReader::rspfDrvrBegin()
{
rspf_c1_ = 0.0;
rspf_c2_ = 0.0;
rspf_rpi_ = 0.0;
rspf_load_pin_ = 0;
rspf_c3_ = 0.0;
rspf_r3_ = 0.0;
}
void
SpfReader::rspfLoadBegin(const char *load_pin_name)
{
rspf_load_pin_ = findPinRelative(load_pin_name);
if (rspf_load_pin_)
pin_node_map_[load_pin_name] = rspf_load_pin_;
else {
pinNotFound(load_pin_name);
stringDelete(load_pin_name);
}
}
void
SpfReader::rspfLoadBegin(const char *load_pin_name,
const char *inst_name,
const char *port_name)
{
Instance *inst = findInstanceRelative(inst_name);
if (inst) {
rspf_load_pin_ = network_->findPinRelative(inst, port_name);
if (rspf_load_pin_)
pin_node_map_[load_pin_name] = rspf_load_pin_;
else {
instPinNotFound(inst_name, port_name);
stringDelete(load_pin_name);
}
}
else {
instNotFound(inst_name);
rspf_load_pin_ = 0;
stringDelete(load_pin_name);
}
stringDelete(inst_name);
stringDelete(port_name);
}
// Note that some SPF writers do not include subnode definitions.
void
SpfReader::subnodeDef(const char *subnode_name)
{
if (is_rspf_)
pin_node_map_[subnode_name] = rspf_subnode_;
else
stringDelete(subnode_name);
}
void
SpfReader::resistor(const char *name,
const char *node1,
const char *node2,
float res)
{
if (is_rspf_) {
if (rspf_drvr_pin_) {
if (rspf_load_pin_ == NULL)
rspfDrvrRes(node1, node2, res);
else
rspfLoadRes(node1, node2, res);
}
stringDelete(name);
}
else
dspfResistor(name, node1, node2, res);
}
void
SpfReader::rspfDrvrRes(const char *node1,
const char *node2,
float res)
{
const Pin *pin1 = pin_node_map_.findKey(node1);
const Pin *pin2 = pin_node_map_.findKey(node2);
// Ignore gnd'd resistors (r1).
if (!((pin1 && pin1 == gnd_net_)
|| (pin2 && pin2 == gnd_net_))) {
if (pin1 && pin1 == rspf_drvr_pin_) {
rspfSubnode(pin2, node2);
rspf_rpi_ = res;
stringDelete(node1);
}
else if (pin2 && pin2 == rspf_drvr_pin_) {
rspfSubnode(pin1, node1);
rspf_rpi_ = res;
stringDelete(node2);
}
else
warn("rspf resistor not connected to driver pin.\n");
}
}
void
SpfReader::rspfSubnode(const Pin *subnode_pin,
const char *subnode_name)
{
// Subnode does not have to be declared before use.
if (subnode_pin != rspf_subnode_)
// Define the driver subnode name.
pin_node_map_[subnode_name] = rspf_subnode_;
else
stringDelete(subnode_name);
}
void
SpfReader::rspfLoadRes(const char *node1,
const char *node2,
float res)
{
rspf_r3_ = res;
stringDelete(node1);
stringDelete(node2);
}
void
SpfReader::capacitor(const char *name,
const char *node1,
const char *node2,
float cap)
{
if (is_rspf_) {
if (rspf_drvr_pin_) {
if (rspf_load_pin_ == NULL)
rspfDrvrCap(node1, node2, cap);
else
rspfLoadCap(node1, node2, cap);
}
stringDelete(name);
}
else
dspfCapacitor(name, node1, node2, cap);
}
void
SpfReader::rspfDrvrCap(const char *node1,
const char *node2,
float cap)
{
const Pin *pin1 = pin_node_map_.findKey(node1);
const Pin *pin2 = pin_node_map_.findKey(node2);
if (pin1 && pin1 == gnd_net_) {
rspfDrvrCap1(node2, pin2, cap);
stringDelete(node1);
}
else if (pin2 && pin2 == gnd_net_) {
rspfDrvrCap1(node1, pin1, cap);
stringDelete(node2);
}
else
warn("capacitor is not grounded.\n");
}
void
SpfReader::rspfDrvrCap1(const char *pin_name,
const Pin *pin,
float cap)
{
if (pin && pin == rspf_drvr_pin_) {
rspf_c2_ = cap;
stringDelete(pin_name);
}
else {
rspfSubnode(pin, pin_name);
rspf_c1_ = cap;
}
}
void
SpfReader::rspfLoadCap(const char *node1,
const char *node2,
float cap)
{
rspf_c3_ = cap;
stringDelete(node1);
stringDelete(node2);
}
void
SpfReader::rspfDrvrFinish()
{
if (rspf_drvr_pin_
// Incremental parasitics do not overwrite existing parasitics.
&& !(increment_ &&
parasitics_->hasPiElmore(rspf_drvr_pin_,
TransRiseFall::rise(), ap_))) {
parasitics_->deletePiElmore(rspf_drvr_pin_, TransRiseFall::rise(), ap_);
parasitics_->deletePiElmore(rspf_drvr_pin_, TransRiseFall::fall(), ap_);
// Only one parasitic, save it under rise transition.
parasitic_ = parasitics_->makePiElmore(rspf_drvr_pin_,
TransRiseFall::rise(), ap_,
rspf_c2_, rspf_rpi_, rspf_c1_);
}
rspf_c2_ = rspf_rpi_ = rspf_c1_ = 0.0;
}
void
SpfReader::rspfLoadFinish()
{
if (parasitic_ && rspf_load_pin_)
parasitics_->setElmore(parasitic_, rspf_load_pin_, rspf_r3_*rspf_c3_);
rspf_load_pin_ = 0;
rspf_r3_ = rspf_c3_ = 0.0;
}
void
SpfReader::rspfNetFinish()
{
rspf_drvr_pin_ = 0;
parasitic_ = 0;
clearPinMap();
}
void
SpfReader::clearPinMap()
{
// Delete the pin names in the pin map.
// Note that erasing the map elements while iterating fails on slowaris,
// so delete all the strings, clear the map and put gnd back in.
SpfPinMap::Iterator node_iter(pin_node_map_);
while (node_iter.hasNext()) {
const char *pin_name;
const Pin *pin;
node_iter.next(pin_name, pin);
if (pin != gnd_net_)
stringDelete(pin_name);
}
pin_node_map_.clear();
pin_node_map_[gnd_net_name_] = gnd_net_;
}
////////////////////////////////////////////////////////////////
void
SpfReader::netBegin(const char *net_name)
{
if (!is_rspf_) {
net_ = findNetRelative(net_name);
if (net_) {
if (increment_
&& parasitics_->hasParasiticNetwork(net_, ap_))
// Do not overwrite existing parasitic.
dspf_ = 0;
else {
parasitics_->deleteParasitics(net_, ap_);
dspf_ = parasitics_->makeParasiticNetwork(net_,pin_cap_included_,ap_);
}
}
else {
netNotFound(net_name);
dspf_ = 0;
}
}
stringDelete(net_name);
}
void
SpfReader::dspfPinDef(const char *pin_name,
const char *pin_type)
{
Pin *pin = findPortPinRelative(pin_name);
if (pin)
pin_node_map_[pin_name] = pin;
else {
pinNotFound(pin_name);
stringDelete(pin_name);
}
stringDelete(pin_type);
}
void
SpfReader::dspfInstPinDef(const char *pin_name,
const char *inst_name,
const char *port_name,
const char *pin_type)
{
Instance *inst = findInstanceRelative(inst_name);
if (inst) {
Pin *pin = network_->findPinRelative(inst, port_name);
if (pin)
pin_node_map_[pin_name] = pin;
else {
instPinNotFound(inst_name, port_name);
stringDelete(pin_name);
}
}
else {
instNotFound(inst_name);
stringDelete(pin_name);
}
stringDelete(inst_name);
stringDelete(port_name);
stringDelete(pin_type);
}
void
SpfReader::dspfResistor(const char *name,
const char *node1,
const char *node2,
float res)
{
if (dspf_) {
ParasiticNode *pnode1 = ensureDspfNode(node1);
ParasiticNode *pnode2 = ensureDspfNode(node2);
if (!keep_device_names_) {
stringDelete(name);
name = 0;
}
if (pnode1 && pnode2)
parasitics_->makeResistor(name, pnode1, pnode2, res, ap_);
}
stringDelete(node1);
stringDelete(node2);
}
ParasiticNode *
SpfReader::ensureDspfNode(const char *node_name)
{
const Pin *pin = pin_node_map_.findKey(node_name);
if (pin)
return parasitics_->ensureParasiticNode(dspf_, pin);
else {
const char *delim = strrchr(node_name, delimiter_);
if (delim) {
const char *id_str = delim + 1;
if (isDigits(id_str)) {
int id = atoi(id_str);
return parasitics_->ensureParasiticNode(dspf_, net_, id);
}
// Fall thru.
}
warn("node %s is not a sub-node or external pin connection\n", node_name);
return 0;
}
}
void
SpfReader::dspfCapacitor(const char *name,
const char *node1,
const char *node2,
float cap)
{
if (dspf_) {
if (stringEq(node1, gnd_net_name_)) {
ParasiticNode *pnode = ensureDspfNode(node2);
if (pnode)
parasitics_->incrCap(pnode, cap, ap_);
stringDelete(name);
}
else if (stringEq(node2, gnd_net_name_)) {
ParasiticNode *pnode = ensureDspfNode(node1);
if (pnode)
parasitics_->incrCap(pnode, cap, ap_);
stringDelete(name);
}
else {
// Coupling capacitor.
ParasiticNode *pnode1 = ensureDspfNode(node1);
ParasiticNode *pnode2 = ensureDspfNode(node2);
if (keep_coupling_caps_
&& pnode1 && pnode2) {
if (!keep_device_names_) {
stringDelete(name);
name = 0;
}
parasitics_->makeCouplingCap(name, pnode1, pnode2, cap, ap_);
}
else {
float scaled_cap = cap * ap_->couplingCapFactor();
if (pnode1)
parasitics_->incrCap(pnode1, scaled_cap, ap_);
if (pnode2)
parasitics_->incrCap(pnode2, scaled_cap, ap_);
stringDelete(name);
}
}
}
stringDelete(node1);
stringDelete(node2);
}
void
SpfReader::dspfNetFinish()
{
if (dspf_) {
if (!quiet_)
parasitics_->check(dspf_);
if (reduce_to_ != reduce_parasitics_to_none) {
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
parasitics_->reduceTo(dspf_, net_, reduce_to_, tr, op_cond_,
corner_, cnst_min_max_, ap_);
}
if (delete_after_reduce_)
parasitics_->deleteParasiticNetwork(net_, ap_);
}
}
clearPinMap();
net_ = 0;
dspf_ = 0;
}
////////////////////////////////////////////////////////////////
float
SpfReader::unitScale(char unit)
{
switch (unit) {
case 'K':
return 1E+3F;
case 'M':
return 1E+6F;
case 'U':
return 1E-6F;
case 'N':
return 1E-9F;
case 'P':
return 1E-12F;
case 'F':
return 1E-15F;
default:
warn("unknown unit suffix %c.\n", unit);
}
return 1.0F;
}
void
SpfReader::pinNotFound(const char *pin_name)
{
warn("pin %s not found.\n", pin_name);
}
void
SpfReader::netNotFound(const char *net_name)
{
warn("net %s not found.\n", net_name);
}
void
SpfReader::instNotFound(const char *inst_name)
{
warn("instance %s not found.\n", inst_name);
}
void
SpfReader::instPinNotFound(const char *inst_name,
const char *port_name)
{
warn("instance %s pin %s not found.\n", inst_name, port_name);
}
} // namespace
// Global namespace
void spfFlushBuffer();
int
SpfParse_error(const char *msg)
{
sta::spf_reader->warn("%s.\n", msg);
spfFlushBuffer();
return 0;
}