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 *