diff --git a/CMakeLists.txt b/CMakeLists.txt
index ad007fe4..02dcd3bc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -175,6 +175,7 @@ set(STA_SOURCE
search/PathVertexRep.cc
search/Power.cc
search/Property.cc
+ search/ReadVcdActivities.cc
search/ReportPath.cc
search/Search.cc
search/SearchPred.cc
diff --git a/search/ReadVcdActivities.cc b/search/ReadVcdActivities.cc
new file mode 100644
index 00000000..fa782ad3
--- /dev/null
+++ b/search/ReadVcdActivities.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 .
+
+#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(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);
+ }
+}
+
+}
diff --git a/search/ReadVcdActivities.hh b/search/ReadVcdActivities.hh
new file mode 100644
index 00000000..e79f5cf4
--- /dev/null
+++ b/search/ReadVcdActivities.hh
@@ -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 .
+
+#pragma once
+
+namespace sta {
+
+class Sta;
+
+void
+readVcdActivities(const char *filename,
+ Sta *sta);
+
+} // namespace
diff --git a/search/Vcd.hh b/search/Vcd.hh
index 33e66304..b0475fe2 100644
--- a/search/Vcd.hh
+++ b/search/Vcd.hh
@@ -37,7 +37,7 @@ typedef vector VcdValues;
typedef int64_t VarTime;
typedef vector VcdScope;
-enum class VcdVarType { wire, reg, parameter };
+enum class VcdVarType { wire, reg, parameter, real };
class Vcd : public StaState
{
@@ -54,6 +54,7 @@ public:
double timeScale() const { return time_scale_; }
void setTimeScale(double time_scale);
const string &timeUnit() const { return time_unit_; }
+ double timeUnitScale() const { return time_unit_scale_; }
void setTimeUnit(const string &time_unit,
double time_unit_scale);
VarTime timeMax() const { return time_max_; }
@@ -127,4 +128,4 @@ private:
uint64_t bus_value_;
};
-}
+} // namespace
diff --git a/search/VcdReader.cc b/search/VcdReader.cc
index 33411f25..ed08b63a 100644
--- a/search/VcdReader.cc
+++ b/search/VcdReader.cc
@@ -21,7 +21,6 @@
#include "Zlib.hh"
#include "Report.hh"
#include "StringUtil.hh"
-#include "StaState.hh"
namespace sta {
@@ -170,6 +169,8 @@ VcdReader::parseVar()
type = VcdVarType::reg;
else if (type_name == "parameter")
type = VcdVarType::parameter;
+ else if (type_name == "real")
+ type = VcdVarType::real;
else
report_->fileError(803, filename_, stmt_line_,
"Unknown variable type %s.",
@@ -221,33 +222,35 @@ VcdReader::parseVarValues()
{
string token = getToken();
while (!token.empty()) {
- if (token[0] == '#') {
+ char char0 = toupper(token[0]);
+ if (char0 == '#') {
prev_time_ = time_;
time_ = stoll(token.substr(1));
if (time_ > prev_time_)
vcd_->setMinDeltaTime(min(time_ - prev_time_, vcd_->minDeltaTime()));
}
- else if (token[0] == '0'
- || token[0] == '1'
- || token[0] == 'X'
- || token[0] == 'U'
- || token[0] == 'Z') {
+ else if (char0 == '0'
+ || char0 == '1'
+ || char0 == 'X'
+ || char0 == 'U'
+ || char0 == 'Z') {
string id = token.substr(1);
if (!vcd_->varIdValid(id))
report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str());
- vcd_->varAppendValue(id, time_, token[0]);
+ vcd_->varAppendValue(id, time_, char0);
}
- else if (token[0] == 'b') {
- if (token[1] == 'X'
- || token[1] == 'U'
- || token[1] == 'Z') {
+ else if (char0 == 'B') {
+ char char1 = toupper(token[1]);
+ if (char1 == 'X'
+ || char1 == 'U'
+ || char1 == 'Z') {
string id = getToken();
if (!vcd_->varIdValid(id))
report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str());
// Bus mixed 0/1/X/U not supported.
- vcd_->varAppendValue(id, time_, token[1]);
+ vcd_->varAppendValue(id, time_, char1);
}
else {
string bin = token.substr(1);
@@ -330,8 +333,7 @@ reportVcdWaveforms(const char *filename,
StaState *sta)
{
- VcdReader reader(sta);
- Vcd vcd = reader.read(filename);
+ Vcd vcd = readVcdFile(filename, sta);
reportWaveforms(vcd, sta->report());
}
diff --git a/tcl/Power.tcl b/tcl/Power.tcl
index 2b611955..bdd9ba42 100644
--- a/tcl/Power.tcl
+++ b/tcl/Power.tcl
@@ -246,6 +246,11 @@ proc set_power_activity { args } {
}
}
+################################################################
+
+# Defined in StaTcl.i
+define_cmd_args "read_vcd_activities" { filename }
+
proc power_find_nan { } {
set corner [cmd_corner]
foreach inst [network_leaf_instances] {
diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i
index e5f5445f..7a261763 100644
--- a/tcl/StaTcl.i
+++ b/tcl/StaTcl.i
@@ -81,6 +81,7 @@
#include "search/ReportPath.hh"
#include "search/Power.hh"
#include "search/VcdReader.hh"
+#include "search/ReadVcdActivities.hh"
namespace sta {
@@ -5008,6 +5009,12 @@ set_power_pin_activity(const Pin *pin,
PwrActivityOrigin::user);
}
+void
+read_vcd_activities(const char *filename)
+{
+ readVcdActivities(filename, Sta::sta());
+}
+
////////////////////////////////////////////////////////////////
EdgeSeq *