2024-09-24 03:04:26 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, Parallax Software, Inc.
|
2024-09-24 03:04:26 +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
|
|
|
|
|
// 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/>.
|
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.
|
2024-09-24 03:04:26 +02:00
|
|
|
|
|
|
|
|
#include "power/SaifReader.hh"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
2024-10-05 04:41:08 +02:00
|
|
|
#include <cinttypes>
|
2024-09-24 03:04:26 +02:00
|
|
|
|
|
|
|
|
#include "Error.hh"
|
|
|
|
|
#include "Debug.hh"
|
2025-02-01 23:49:30 +01:00
|
|
|
#include "Stats.hh"
|
2024-09-24 03:04:26 +02:00
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Network.hh"
|
2025-01-16 00:20:21 +01:00
|
|
|
#include "PortDirection.hh"
|
2024-09-24 03:04:26 +02:00
|
|
|
#include "Sdc.hh"
|
|
|
|
|
#include "Power.hh"
|
|
|
|
|
#include "power/SaifReaderPvt.hh"
|
2025-02-01 23:49:30 +01:00
|
|
|
#include "power/SaifScanner.hh"
|
2024-09-24 03:04:26 +02:00
|
|
|
#include "Sta.hh"
|
|
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
using std::min;
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
readSaif(const char *filename,
|
|
|
|
|
const char *scope,
|
|
|
|
|
Sta *sta)
|
|
|
|
|
{
|
|
|
|
|
SaifReader reader(filename, scope, sta);
|
|
|
|
|
bool success = reader.read();
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SaifReader::SaifReader(const char *filename,
|
|
|
|
|
const char *scope,
|
|
|
|
|
Sta *sta) :
|
|
|
|
|
StaState(sta),
|
|
|
|
|
filename_(filename),
|
|
|
|
|
scope_(scope),
|
|
|
|
|
divider_('/'),
|
|
|
|
|
escape_('\\'),
|
|
|
|
|
timescale_(1.0E-9F), // default units of ns
|
|
|
|
|
duration_(0.0),
|
|
|
|
|
in_scope_level_(0),
|
|
|
|
|
power_(sta->power())
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
SaifReader::read()
|
|
|
|
|
{
|
2025-02-01 23:49:30 +01:00
|
|
|
gzstream::igzstream stream(filename_);
|
|
|
|
|
if (stream.is_open()) {
|
|
|
|
|
Stats stats(debug_, report_);
|
|
|
|
|
SaifScanner scanner(&stream, filename_, this, report_);
|
|
|
|
|
SaifParse parser(&scanner, this);
|
2024-09-24 03:04:26 +02:00
|
|
|
// yyparse returns 0 on success.
|
2025-02-01 23:49:30 +01:00
|
|
|
bool success = (parser.parse() == 0);
|
2024-12-31 22:59:20 +01:00
|
|
|
report_->reportLine("Annotated %zu pin activities.", annotated_pins_.size());
|
2024-09-24 03:04:26 +02:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw FileNotReadable(filename_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::setDivider(char divider)
|
|
|
|
|
{
|
|
|
|
|
divider_ = divider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::setTimescale(uint64_t multiplier,
|
|
|
|
|
const char *units)
|
|
|
|
|
{
|
|
|
|
|
if (multiplier == 1
|
|
|
|
|
|| multiplier == 10
|
|
|
|
|
|| multiplier == 100) {
|
|
|
|
|
if (stringEq(units, "us"))
|
|
|
|
|
timescale_ = multiplier * 1E-6;
|
|
|
|
|
else if (stringEq(units, "ns"))
|
|
|
|
|
timescale_ = multiplier * 1E-9;
|
|
|
|
|
else if (stringEq(units, "ps"))
|
|
|
|
|
timescale_ = multiplier * 1E-12;
|
|
|
|
|
else if (stringEq(units, "fs"))
|
|
|
|
|
timescale_ = multiplier * 1E-15;
|
|
|
|
|
else
|
2025-02-01 23:49:30 +01:00
|
|
|
report_->error(180, "SAIF TIMESCALE units not us, ns, or ps.");
|
2024-09-24 03:04:26 +02:00
|
|
|
}
|
|
|
|
|
else
|
2025-02-01 23:49:30 +01:00
|
|
|
report_->error(181, "SAIF TIMESCALE multiplier not 1, 10, or 100.");
|
2024-09-24 03:04:26 +02:00
|
|
|
stringDelete(units);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::setDuration(uint64_t duration)
|
|
|
|
|
{
|
|
|
|
|
duration_ = duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::instancePush(const char *instance_name)
|
|
|
|
|
{
|
|
|
|
|
if (in_scope_level_ == 0) {
|
|
|
|
|
// Check for a match to the annotation scope.
|
|
|
|
|
saif_scope_.push_back(instance_name);
|
|
|
|
|
|
|
|
|
|
string saif_scope;
|
|
|
|
|
bool first = true;
|
|
|
|
|
for (string &inst : saif_scope_) {
|
|
|
|
|
if (!first)
|
|
|
|
|
saif_scope += network_->pathDivider();
|
|
|
|
|
saif_scope += inst;
|
|
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
if (stringEq(saif_scope.c_str(), scope_))
|
|
|
|
|
in_scope_level_ = saif_scope_.size();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Inside annotation scope.
|
|
|
|
|
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
|
|
|
|
Instance *child = network_->findChild(parent, instance_name);
|
|
|
|
|
path_.push_back(child);
|
|
|
|
|
}
|
|
|
|
|
stringDelete(instance_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::instancePop()
|
|
|
|
|
{
|
|
|
|
|
if (in_scope_level_ == 0)
|
|
|
|
|
saif_scope_.pop_back();
|
|
|
|
|
if (!path_.empty())
|
|
|
|
|
path_.pop_back();
|
|
|
|
|
if (saif_scope_.size() < in_scope_level_)
|
|
|
|
|
in_scope_level_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SaifReader::setNetDurations(const char *net_name,
|
|
|
|
|
SaifStateDurations &durations)
|
|
|
|
|
{
|
|
|
|
|
if (in_scope_level_ > 0) {
|
|
|
|
|
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
|
|
|
|
if (parent) {
|
2024-10-11 22:52:43 +02:00
|
|
|
string unescaped_name = unescaped(net_name);
|
|
|
|
|
const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str());
|
2025-01-16 00:20:21 +01:00
|
|
|
if (pin
|
|
|
|
|
&& !sdc_network_->isHierarchical(pin)
|
|
|
|
|
&& !sdc_network_->direction(pin)->isInternal()) {
|
2024-09-24 03:04:26 +02:00
|
|
|
double t1 = durations[static_cast<int>(SaifState::T1)];
|
|
|
|
|
float duty = t1 / duration_;
|
|
|
|
|
double tc = durations[static_cast<int>(SaifState::TC)];
|
2025-01-17 21:02:13 +01:00
|
|
|
float density = tc / (duration_ * timescale_);
|
2024-09-24 03:04:26 +02:00
|
|
|
debugPrint(debug_, "read_saif", 2,
|
2025-01-17 21:02:13 +01:00
|
|
|
"%s duty %.0f / %" PRIu64 " = %.2f tc %.0f density %.2f",
|
2024-09-24 03:04:26 +02:00
|
|
|
sdc_network_->pathName(pin),
|
|
|
|
|
t1,
|
|
|
|
|
duration_,
|
|
|
|
|
duty,
|
|
|
|
|
tc,
|
2025-01-17 21:02:13 +01:00
|
|
|
density);
|
|
|
|
|
power_->setUserActivity(pin, density, duty, PwrActivityOrigin::saif);
|
2024-09-24 03:04:26 +02:00
|
|
|
annotated_pins_.insert(pin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-11 22:52:43 +02:00
|
|
|
stringDelete(net_name);
|
2024-09-24 03:04:26 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-11 22:52:43 +02:00
|
|
|
string
|
2024-09-24 03:04:26 +02:00
|
|
|
SaifReader::unescaped(const char *token)
|
|
|
|
|
{
|
2024-10-11 22:52:43 +02:00
|
|
|
string unescaped;
|
|
|
|
|
for (const char *t = token; *t; t++) {
|
|
|
|
|
char ch = *t;
|
2025-04-05 00:23:40 +02:00
|
|
|
if (ch != escape_)
|
2024-09-24 03:04:26 +02:00
|
|
|
// Just the normal noises.
|
2024-10-11 22:52:43 +02:00
|
|
|
unescaped += ch;
|
2024-09-24 03:04:26 +02:00
|
|
|
}
|
2024-10-11 22:52:43 +02:00
|
|
|
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped.c_str());
|
2024-09-24 03:04:26 +02:00
|
|
|
return unescaped;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-01 23:49:30 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
2024-09-24 03:04:26 +02:00
|
|
|
|
2025-02-01 23:49:30 +01:00
|
|
|
SaifScanner::SaifScanner(std::istream *stream,
|
|
|
|
|
const string &filename,
|
|
|
|
|
SaifReader *reader,
|
|
|
|
|
Report *report) :
|
|
|
|
|
yyFlexLexer(stream),
|
|
|
|
|
filename_(filename),
|
|
|
|
|
reader_(reader),
|
|
|
|
|
report_(report)
|
2024-09-24 03:04:26 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-02-01 23:49:30 +01:00
|
|
|
SaifScanner::error(const char *msg)
|
2024-09-24 03:04:26 +02:00
|
|
|
{
|
2025-02-12 18:33:13 +01:00
|
|
|
report_->fileError(1868, filename_.c_str(), lineno(), "%s", msg);
|
2024-09-24 03:04:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|