read_vcd_activities
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
c2e15cd9ee
commit
d1c899a5c3
|
|
@ -175,6 +175,7 @@ set(STA_SOURCE
|
||||||
search/PathVertexRep.cc
|
search/PathVertexRep.cc
|
||||||
search/Power.cc
|
search/Power.cc
|
||||||
search/Property.cc
|
search/Property.cc
|
||||||
|
search/ReadVcdActivities.cc
|
||||||
search/ReportPath.cc
|
search/ReportPath.cc
|
||||||
search/Search.cc
|
search/Search.cc
|
||||||
search/SearchPred.cc
|
search/SearchPred.cc
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
// OpenSTA, Static Timing Analyzer
|
||||||
|
// Copyright (c) 2022, 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 "ReadVcdActivities.hh"
|
||||||
|
|
||||||
|
#include "VcdReader.hh"
|
||||||
|
#include "Debug.hh"
|
||||||
|
#include "Network.hh"
|
||||||
|
#include "VerilogNamespace.hh"
|
||||||
|
#include "ParseBus.hh"
|
||||||
|
#include "Sdc.hh"
|
||||||
|
#include "Power.hh"
|
||||||
|
#include "Sta.hh"
|
||||||
|
|
||||||
|
namespace sta {
|
||||||
|
|
||||||
|
using std::min;
|
||||||
|
using std::swap;
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
|
static void
|
||||||
|
setVcdActivities(Vcd &vcd,
|
||||||
|
Sta *sta);
|
||||||
|
static void
|
||||||
|
setPinActivity(const char *pin_name,
|
||||||
|
int transition_count,
|
||||||
|
float activity,
|
||||||
|
float duty,
|
||||||
|
Debug *debug,
|
||||||
|
Network *network,
|
||||||
|
Power *power);
|
||||||
|
void
|
||||||
|
readVcdActivities(const char *filename,
|
||||||
|
Sta *sta)
|
||||||
|
{
|
||||||
|
Vcd vcd = readVcdFile(filename, sta);
|
||||||
|
setVcdActivities(vcd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setVcdActivities(Vcd &vcd,
|
||||||
|
Sta *sta)
|
||||||
|
{
|
||||||
|
Debug *debug = sta->debug();
|
||||||
|
Network *network = sta->network();
|
||||||
|
Power *power = sta->power();
|
||||||
|
|
||||||
|
float clk_period = 0.0;
|
||||||
|
for (Clock *clk : *sta->sdc()->clocks())
|
||||||
|
clk_period = min(clk->period(), clk_period);
|
||||||
|
|
||||||
|
VarTime time_max = vcd.timeMax();
|
||||||
|
for (VcdVar &var : vcd.vars()) {
|
||||||
|
const VcdValues &var_values = vcd.values(var);
|
||||||
|
if (!var_values.empty()) {
|
||||||
|
int transition_count = 0;
|
||||||
|
char prev_value = var_values[0].value();
|
||||||
|
VarTime prev_time = var_values[0].time();
|
||||||
|
VarTime high_time = 0;
|
||||||
|
for (const VcdValue &var_value : var_values) {
|
||||||
|
VarTime time = var_value.time();
|
||||||
|
char value = var_value.value();
|
||||||
|
if (prev_value == '1')
|
||||||
|
high_time += time - prev_time;
|
||||||
|
transition_count++;
|
||||||
|
prev_time = time;
|
||||||
|
prev_value = value;
|
||||||
|
}
|
||||||
|
if (prev_value == '1')
|
||||||
|
high_time += time_max - prev_time;
|
||||||
|
float duty = static_cast<float>(high_time) / time_max;
|
||||||
|
float activity = transition_count
|
||||||
|
/ (time_max * vcd.timeUnitScale() / clk_period);
|
||||||
|
|
||||||
|
string var_name = var.name();
|
||||||
|
if (var_name[0] == '\\')
|
||||||
|
var_name += ' ';
|
||||||
|
const char *sta_name = verilogToSta(var_name.c_str());
|
||||||
|
if (var.width() == 1) {
|
||||||
|
setPinActivity(sta_name, transition_count, activity, duty,
|
||||||
|
debug, network, power);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char *bus_name;
|
||||||
|
int from, to;
|
||||||
|
parseBusRange(sta_name, '[', ']', '\\',
|
||||||
|
bus_name, from, to);
|
||||||
|
if (from > to)
|
||||||
|
swap(from, to);
|
||||||
|
for (int bit = from; bit <= to; bit++) {
|
||||||
|
string name = bus_name;
|
||||||
|
name += '[';
|
||||||
|
name += to_string(bit);
|
||||||
|
name += ']';
|
||||||
|
setPinActivity(name.c_str(), transition_count, activity, duty,
|
||||||
|
debug, network, power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setPinActivity(const char *pin_name,
|
||||||
|
int transition_count,
|
||||||
|
float activity,
|
||||||
|
float duty,
|
||||||
|
Debug *debug,
|
||||||
|
Network *network,
|
||||||
|
Power *power)
|
||||||
|
{
|
||||||
|
Pin *pin = network->findPin(pin_name);
|
||||||
|
if (pin) {
|
||||||
|
debugPrint(debug, "vcd_activities", 1,
|
||||||
|
"%s transitions %d activity %.2f duty %.2f",
|
||||||
|
pin_name,
|
||||||
|
transition_count,
|
||||||
|
activity,
|
||||||
|
duty);
|
||||||
|
power->setUserActivity(pin, activity, duty,
|
||||||
|
PwrActivityOrigin::user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// OpenSTA, Static Timing Analyzer
|
||||||
|
// Copyright (c) 2022, 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/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sta {
|
||||||
|
|
||||||
|
class Sta;
|
||||||
|
|
||||||
|
void
|
||||||
|
readVcdActivities(const char *filename,
|
||||||
|
Sta *sta);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
@ -37,7 +37,7 @@ typedef vector<VcdValue> VcdValues;
|
||||||
typedef int64_t VarTime;
|
typedef int64_t VarTime;
|
||||||
typedef vector<string> VcdScope;
|
typedef vector<string> VcdScope;
|
||||||
|
|
||||||
enum class VcdVarType { wire, reg, parameter };
|
enum class VcdVarType { wire, reg, parameter, real };
|
||||||
|
|
||||||
class Vcd : public StaState
|
class Vcd : public StaState
|
||||||
{
|
{
|
||||||
|
|
@ -54,6 +54,7 @@ public:
|
||||||
double timeScale() const { return time_scale_; }
|
double timeScale() const { return time_scale_; }
|
||||||
void setTimeScale(double time_scale);
|
void setTimeScale(double time_scale);
|
||||||
const string &timeUnit() const { return time_unit_; }
|
const string &timeUnit() const { return time_unit_; }
|
||||||
|
double timeUnitScale() const { return time_unit_scale_; }
|
||||||
void setTimeUnit(const string &time_unit,
|
void setTimeUnit(const string &time_unit,
|
||||||
double time_unit_scale);
|
double time_unit_scale);
|
||||||
VarTime timeMax() const { return time_max_; }
|
VarTime timeMax() const { return time_max_; }
|
||||||
|
|
@ -127,4 +128,4 @@ private:
|
||||||
uint64_t bus_value_;
|
uint64_t bus_value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
#include "Zlib.hh"
|
#include "Zlib.hh"
|
||||||
#include "Report.hh"
|
#include "Report.hh"
|
||||||
#include "StringUtil.hh"
|
#include "StringUtil.hh"
|
||||||
#include "StaState.hh"
|
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -170,6 +169,8 @@ VcdReader::parseVar()
|
||||||
type = VcdVarType::reg;
|
type = VcdVarType::reg;
|
||||||
else if (type_name == "parameter")
|
else if (type_name == "parameter")
|
||||||
type = VcdVarType::parameter;
|
type = VcdVarType::parameter;
|
||||||
|
else if (type_name == "real")
|
||||||
|
type = VcdVarType::real;
|
||||||
else
|
else
|
||||||
report_->fileError(803, filename_, stmt_line_,
|
report_->fileError(803, filename_, stmt_line_,
|
||||||
"Unknown variable type %s.",
|
"Unknown variable type %s.",
|
||||||
|
|
@ -221,33 +222,35 @@ VcdReader::parseVarValues()
|
||||||
{
|
{
|
||||||
string token = getToken();
|
string token = getToken();
|
||||||
while (!token.empty()) {
|
while (!token.empty()) {
|
||||||
if (token[0] == '#') {
|
char char0 = toupper(token[0]);
|
||||||
|
if (char0 == '#') {
|
||||||
prev_time_ = time_;
|
prev_time_ = time_;
|
||||||
time_ = stoll(token.substr(1));
|
time_ = stoll(token.substr(1));
|
||||||
if (time_ > prev_time_)
|
if (time_ > prev_time_)
|
||||||
vcd_->setMinDeltaTime(min(time_ - prev_time_, vcd_->minDeltaTime()));
|
vcd_->setMinDeltaTime(min(time_ - prev_time_, vcd_->minDeltaTime()));
|
||||||
}
|
}
|
||||||
else if (token[0] == '0'
|
else if (char0 == '0'
|
||||||
|| token[0] == '1'
|
|| char0 == '1'
|
||||||
|| token[0] == 'X'
|
|| char0 == 'X'
|
||||||
|| token[0] == 'U'
|
|| char0 == 'U'
|
||||||
|| token[0] == 'Z') {
|
|| char0 == 'Z') {
|
||||||
string id = token.substr(1);
|
string id = token.substr(1);
|
||||||
if (!vcd_->varIdValid(id))
|
if (!vcd_->varIdValid(id))
|
||||||
report_->fileError(804, filename_, stmt_line_,
|
report_->fileError(804, filename_, stmt_line_,
|
||||||
"unknown variable %s", id.c_str());
|
"unknown variable %s", id.c_str());
|
||||||
vcd_->varAppendValue(id, time_, token[0]);
|
vcd_->varAppendValue(id, time_, char0);
|
||||||
}
|
}
|
||||||
else if (token[0] == 'b') {
|
else if (char0 == 'B') {
|
||||||
if (token[1] == 'X'
|
char char1 = toupper(token[1]);
|
||||||
|| token[1] == 'U'
|
if (char1 == 'X'
|
||||||
|| token[1] == 'Z') {
|
|| char1 == 'U'
|
||||||
|
|| char1 == 'Z') {
|
||||||
string id = getToken();
|
string id = getToken();
|
||||||
if (!vcd_->varIdValid(id))
|
if (!vcd_->varIdValid(id))
|
||||||
report_->fileError(804, filename_, stmt_line_,
|
report_->fileError(804, filename_, stmt_line_,
|
||||||
"unknown variable %s", id.c_str());
|
"unknown variable %s", id.c_str());
|
||||||
// Bus mixed 0/1/X/U not supported.
|
// Bus mixed 0/1/X/U not supported.
|
||||||
vcd_->varAppendValue(id, time_, token[1]);
|
vcd_->varAppendValue(id, time_, char1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string bin = token.substr(1);
|
string bin = token.substr(1);
|
||||||
|
|
@ -330,8 +333,7 @@ reportVcdWaveforms(const char *filename,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
|
|
||||||
{
|
{
|
||||||
VcdReader reader(sta);
|
Vcd vcd = readVcdFile(filename, sta);
|
||||||
Vcd vcd = reader.read(filename);
|
|
||||||
reportWaveforms(vcd, sta->report());
|
reportWaveforms(vcd, sta->report());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,11 @@ proc set_power_activity { args } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# Defined in StaTcl.i
|
||||||
|
define_cmd_args "read_vcd_activities" { filename }
|
||||||
|
|
||||||
proc power_find_nan { } {
|
proc power_find_nan { } {
|
||||||
set corner [cmd_corner]
|
set corner [cmd_corner]
|
||||||
foreach inst [network_leaf_instances] {
|
foreach inst [network_leaf_instances] {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@
|
||||||
#include "search/ReportPath.hh"
|
#include "search/ReportPath.hh"
|
||||||
#include "search/Power.hh"
|
#include "search/Power.hh"
|
||||||
#include "search/VcdReader.hh"
|
#include "search/VcdReader.hh"
|
||||||
|
#include "search/ReadVcdActivities.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -5008,6 +5009,12 @@ set_power_pin_activity(const Pin *pin,
|
||||||
PwrActivityOrigin::user);
|
PwrActivityOrigin::user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
read_vcd_activities(const char *filename)
|
||||||
|
{
|
||||||
|
readVcdActivities(filename, Sta::sta());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
EdgeSeq *
|
EdgeSeq *
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue