read_vcd_activities

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2022-10-27 17:35:58 -07:00
commit cecb8cda7e
17 changed files with 1037 additions and 74 deletions

View File

@ -173,7 +173,6 @@ set(STA_SOURCE
search/PathRef.cc
search/PathVertex.cc
search/PathVertexRep.cc
search/Power.cc
search/Property.cc
search/ReportPath.cc
search/Search.cc
@ -189,6 +188,11 @@ set(STA_SOURCE
search/WorstSlack.cc
search/WritePathSpice.cc
power/Power.cc
power/ReadVcdActivities.cc
power/Vcd.cc
power/VcdReader.cc
util/Debug.cc
util/DispatchQueue.cc
util/Error.cc
@ -227,10 +231,10 @@ set(STA_TCL_FILES
tcl/Cmds.tcl
tcl/Variables.tcl
tcl/Sta.tcl
tcl/Power.tcl
tcl/Splash.tcl
dcalc/DelayCalc.tcl
parasitics/Parasitics.tcl
power/Power.tcl
sdf/Sdf.tcl
verilog/Verilog.tcl
)
@ -313,18 +317,20 @@ set_property(SOURCE ${STA_SWIG_FILE}
-I${STA_HOME}/sdf
-I${STA_HOME}/dcalc
-I${STA_HOME}/parasitics
-I${STA_HOME}/power
-I${STA_HOME}/verilog
)
set_property(SOURCE ${STA_SWIG_FILE}
PROPERTY DEPENDS
${STA_HOME}/dcalc/DelayCalc.i
${STA_HOME}/parasitics/Parasitics.i
${STA_HOME}/power/Power.i
${STA_HOME}/sdf/Sdf.i
${STA_HOME}/tcl/Exception.i
${STA_HOME}/tcl/StaTcl.i
${STA_HOME}/verilog/Verilog.i
${STA_HOME}/tcl/NetworkEdit.i
${STA_HOME}/sdf/Sdf.i
${STA_HOME}/parasitics/Parasitics.i
${STA_HOME}/dcalc/DelayCalc.i
${STA_HOME}/verilog/Verilog.i
)
swig_add_library(sta_swig

View File

@ -23,3 +23,4 @@
%include "Sdf.i"
%include "DelayCalc.i"
%include "Parasitics.i"
%include "Power.i"

Binary file not shown.

Binary file not shown.

View File

@ -41,8 +41,8 @@
#include "GraphDelayCalc.hh"
#include "Corner.hh"
#include "PathVertex.hh"
#include "Levelize.hh"
#include "Sim.hh"
#include "search/Levelize.hh"
#include "search/Sim.hh"
#include "Search.hh"
#include "Bfs.hh"
#include "ClkNetwork.hh"

124
power/Power.i Normal file
View File

@ -0,0 +1,124 @@
%module power
%{
// 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 "Sta.hh"
#include "power/Power.hh"
#include "power/VcdReader.hh"
#include "power/ReadVcdActivities.hh"
namespace sta {
typedef FloatSeq TmpFloatSeq;
} // namespace
using namespace sta;
%}
%typemap(out) TmpFloatSeq* {
FloatSeq *floats = $1;
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
if (floats) {
for (unsigned i = 0; i < floats->size(); i++) {
Tcl_Obj *obj = Tcl_NewDoubleObj((*floats)[i]);
Tcl_ListObjAppendElement(interp, list, obj);
}
delete floats;
}
Tcl_SetObjResult(interp, list);
}
%inline %{
TmpFloatSeq *
design_power(const Corner *corner)
{
cmdLinkedNetwork();
PowerResult total, sequential, combinational, macro, pad;
Sta::sta()->power(corner, total, sequential, combinational, macro, pad);
FloatSeq *floats = new FloatSeq;
pushPowerResultFloats(total, floats);
pushPowerResultFloats(sequential, floats);
pushPowerResultFloats(combinational, floats);
pushPowerResultFloats(macro, floats);
pushPowerResultFloats(pad, floats);
return floats;
}
TmpFloatSeq *
instance_power(Instance *inst,
const Corner *corner)
{
cmdLinkedNetwork();
PowerResult power;
Sta::sta()->power(inst, corner, power);
FloatSeq *floats = new FloatSeq;
floats->push_back(power.internal());
floats->push_back(power.switching());
floats->push_back(power.leakage());
floats->push_back(power.total());
return floats;
}
void
set_power_global_activity(float activity,
float duty)
{
Sta::sta()->power()->setGlobalActivity(activity, duty);
}
void
set_power_input_activity(float activity,
float duty)
{
return Sta::sta()->power()->setInputActivity(activity, duty);
}
void
set_power_input_port_activity(const Port *input_port,
float activity,
float duty)
{
return Sta::sta()->power()->setInputPortActivity(input_port, activity, duty);
}
void
set_power_pin_activity(const Pin *pin,
float activity,
float duty)
{
return Sta::sta()->power()->setUserActivity(pin, activity, duty,
PwrActivityOrigin::user);
}
void
read_vcd_activities(const char *filename)
{
readVcdActivities(filename, Sta::sta());
}
void
report_vcd_waveforms(const char *filename)
{
reportVcdWaveforms(filename, Sta::sta());
}
%} // inline

View File

@ -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] {

138
power/ReadVcdActivities.cc Normal file
View File

@ -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);
}
}
}

View File

@ -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

151
power/Vcd.cc Normal file
View File

@ -0,0 +1,151 @@
// 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 "Vcd.hh"
#include "Report.hh"
namespace sta {
Vcd::Vcd(StaState *sta) :
StaState(sta),
time_unit_scale_(0.0),
max_var_name_length_(0),
max_var_width_(0),
time_max_(0)
{
}
////////////////////////////////////////////////////////////////
void
Vcd::setTimeUnit(const string &time_unit,
double time_unit_scale)
{
time_unit_ = time_unit;
time_unit_scale_ = time_unit_scale;
}
void
Vcd::setDate(const string &date)
{
date_ = date;
}
void
Vcd::setComment(const string &comment)
{
comment_ = comment;
}
void
Vcd::setVersion(const string &version)
{
version_ = version;
}
void
Vcd::setTimeScale(double time_scale)
{
time_scale_ = time_scale;
}
void
Vcd::setMinDeltaTime(VarTime min_delta_time)
{
min_delta_time_ = min_delta_time;
}
void
Vcd::setTimeMax(VarTime time_max)
{
time_max_ = time_max;
}
void
Vcd::makeVar(string &name,
VcdVarType type,
int width,
string &id)
{
vars_.push_back(VcdVar(name, type, width, id));
max_var_name_length_ = std::max(max_var_name_length_, name.size());
max_var_width_ = std::max(max_var_width_, width);
// Make entry for var ID.
id_values_map_[id].clear();
}
bool
Vcd::varIdValid(string &id)
{
return id_values_map_.find(id) != id_values_map_.end();
}
void
Vcd::varAppendValue(string &id,
VarTime time,
char value)
{
VcdValues &values = id_values_map_[id];
values.push_back(VcdValue(time, value, 0));
}
void
Vcd::varAppendBusValue(string &id,
VarTime time,
int64_t bus_value)
{
VcdValues &values = id_values_map_[id];
values.push_back(VcdValue(time, '\0', bus_value));
}
VcdValues &
Vcd::values(VcdVar &var)
{
if (id_values_map_.find(var.id()) == id_values_map_.end()) {
report_->error(805, "Unknown variable %s ID %s",
var.name().c_str(),
var.id().c_str());
static VcdValues empty;
return empty;
}
else
return id_values_map_[var.id()];
}
////////////////////////////////////////////////////////////////
VcdVar::VcdVar(string name,
VcdVarType type,
int width,
string id) :
name_(name),
type_(type),
width_(width),
id_(id)
{
}
VcdValue::VcdValue(VarTime time,
char value,
uint64_t bus_value) :
time_(time),
value_(value),
bus_value_(bus_value)
{
}
}

131
power/Vcd.hh Normal file
View File

@ -0,0 +1,131 @@
// 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
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include "StaState.hh"
namespace sta {
using std::string;
using std::vector;
using std::map;
using std::max;
using std::min;
class VcdVar;
class VcdValue;
typedef vector<VcdValue> VcdValues;
typedef int64_t VarTime;
typedef vector<string> VcdScope;
enum class VcdVarType { wire, reg, parameter, real };
class Vcd : public StaState
{
public:
Vcd(StaState *sta);
VcdValues &values(VcdVar &var);
const string &date() const { return date_; }
void setDate(const string &date);
const string &comment() const { return comment_; }
void setComment(const string &comment);
const string &version() const { return version_; }
void setVersion(const string &version);
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_; }
void setTimeMax(VarTime time_max);
VarTime minDeltaTime() const { return min_delta_time_; }
void setMinDeltaTime(VarTime min_delta_time);
vector<VcdVar> vars() { return vars_; }
void makeVar(string &name,
VcdVarType type,
int width,
string &id);
int maxVarWidth() const { return max_var_width_; }
int maxVarNameLength() const { return max_var_name_length_; }
bool varIdValid(string &id);
void varAppendValue(string &id,
VarTime time,
char value);
void varAppendBusValue(string &id,
VarTime time,
int64_t bus_value);
private:
string date_;
string comment_;
string version_;
double time_scale_;
string time_unit_;
double time_unit_scale_;
vector<VcdVar> vars_;
size_t max_var_name_length_;
int max_var_width_;
map<string, VcdValues> id_values_map_;
VarTime min_delta_time_;
VarTime time_max_;
};
class VcdVar
{
public:
VcdVar(string name,
VcdVarType type,
int width,
string id);
const string& name() const { return name_; }
VcdVarType type() const { return type_; }
int width() const { return width_; }
const string& id() const { return id_; }
private:
string name_;
VcdVarType type_;
int width_;
string id_;
};
class VcdValue
{
public:
VcdValue(VarTime time,
char value,
uint64_t bus_value);
VarTime time() const { return time_; }
char value() const { return value_; }
uint64_t busValue() const { return bus_value_; }
private:
VarTime time_;
// 01XUZ or '\0' when width > 1 to use bus_value_.
char value_;
uint64_t bus_value_;
};
} // namespace

411
power/VcdReader.cc Normal file
View File

@ -0,0 +1,411 @@
// 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 <cctype>
#include "VcdReader.hh"
#include "Zlib.hh"
#include "Report.hh"
#include "StringUtil.hh"
namespace sta {
using std::isspace;
// Very imprecise syntax definition
// https://en.wikipedia.org/wiki/Value_change_dump#Structure.2FSyntax
// Much better syntax definition
// https://web.archive.org/web/20120323132708/http://www.beyondttl.com/vcd.php
class VcdReader : public StaState
{
public:
VcdReader(StaState *sta);
Vcd read(const char *filename);
private:
void parseTimescale();
void setTimeUnit(const string &time_unit);
void parseVar();
void parseScope();
void parseUpscope();
void parseVarValues();
string getToken();
string readStmtString();
vector<string> readStmtTokens();
gzFile stream_;
string token_;
const char *filename_;
int file_line_;
int stmt_line_;
Vcd *vcd_;
VarTime time_;
VarTime prev_time_;
VcdScope scope_;
};
Vcd
readVcdFile(const char *filename,
StaState *sta)
{
VcdReader reader(sta);
return reader.read(filename);
}
Vcd
VcdReader::read(const char *filename)
{
Vcd vcd(this);
vcd_ = &vcd;
stream_ = gzopen(filename, "r");
if (stream_) {
filename_ = filename;
file_line_ = 1;
stmt_line_ = 1;
string token = getToken();
while (!token.empty()) {
if (token == "$date")
vcd_->setDate(readStmtString());
else if (token == "$comment")
vcd_->setComment(readStmtString());
else if (token == "$version")
vcd_->setVersion(readStmtString());
else if (token == "$timescale")
parseTimescale();
else if (token == "$var")
parseVar();
else if (token == "$scope")
parseScope();
else if (token == "$upscope")
parseUpscope();
else if (token == "$enddefinitions")
// empty body
readStmtString();
else if (token == "$dumpall")
parseVarValues();
else if (token == "$dumpvars")
// Initial values.
parseVarValues();
else if (token[0] == '$')
report_->fileError(800, filename_, stmt_line_, "unhandled vcd command.");
else
parseVarValues();
token = getToken();
}
gzclose(stream_);
}
return vcd;
}
VcdReader::VcdReader(StaState *sta) :
StaState(sta),
stmt_line_(0),
vcd_(nullptr),
time_(0),
prev_time_(0)
{
}
void
VcdReader::parseTimescale()
{
vector<string> tokens = readStmtTokens();
if (tokens.size() == 1) {
size_t last;
vcd_->setTimeScale(std::stod(tokens[0], &last));
setTimeUnit(tokens[0].substr(last));
}
else if (tokens.size() == 2) {
vcd_->setTimeScale(std::stod(tokens[0]));
setTimeUnit(tokens[1]);
}
else
report_->fileError(800, filename_, stmt_line_, "timescale syntax error.");
}
void
VcdReader::setTimeUnit(const string &time_unit)
{
double time_unit_scale = 1.0;
if (time_unit == "fs")
time_unit_scale = 1e-15;
else if (time_unit == "ps")
time_unit_scale = 1e-12;
else if (time_unit == "ns")
time_unit_scale = 1e-9;
else
report_->fileError(801, filename_, stmt_line_, "Unknown timescale unit.");
vcd_->setTimeUnit(time_unit, time_unit_scale);;
}
void
VcdReader::parseVar()
{
vector<string> tokens = readStmtTokens();
if (tokens.size() == 4
|| tokens.size() == 5) {
string type_name = tokens[0];
VcdVarType type = VcdVarType::wire;
if (type_name == "wire")
type = VcdVarType::wire;
else if (type_name == "reg")
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.",
type_name.c_str());
int width = stoi(tokens[1]);
string id = tokens[2];
string name;
int level = 0;
for (string &context : scope_) {
// Skip the first 2 levels of scope.
// -test bench module
// -design instance
if (level > 1) {
name += context;
name += '/';
}
level++;
}
name += tokens[3];
// iverilog separates bus base name from bit range.
if (tokens.size() == 5)
name += tokens[4];
vcd_->makeVar(name, type, width, id);
}
else
report_->fileError(802, filename_, stmt_line_, "Variable syntax error.");
}
void
VcdReader::parseScope()
{
vector<string> tokens = readStmtTokens();
string &scope = tokens[1];
scope_.push_back(scope);
}
void
VcdReader::parseUpscope()
{
readStmtTokens();
scope_.pop_back();
}
void
VcdReader::parseVarValues()
{
string token = getToken();
while (!token.empty()) {
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 (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_, char0);
}
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_, char1);
}
else {
string bin = token.substr(1);
char *end;
int64_t bus_value = strtol(bin.c_str(), &end, 2);
string id = getToken();
if (!vcd_->varIdValid(id))
report_->fileError(804, filename_, stmt_line_,
"unknown variable %s", id.c_str());
else
vcd_->varAppendBusValue(id, time_, bus_value);
}
}
token = getToken();
}
vcd_->setTimeMax(time_);
}
string
VcdReader::readStmtString()
{
stmt_line_ = file_line_;
string line;
string token = getToken();
while (!token.empty() && token != "$end") {
if (!line.empty())
line += " ";
line += token;
token = getToken();
}
return line;
}
vector<string>
VcdReader::readStmtTokens()
{
stmt_line_ = file_line_;
vector<string> tokens;
string token = getToken();
while (!token.empty() && token != "$end") {
tokens.push_back(token);
token = getToken();
}
return tokens;
}
string
VcdReader::getToken()
{
string token;
int ch = gzgetc(stream_);
if (ch == '\n')
file_line_++;
// skip whitespace
while (ch != EOF && isspace(ch)) {
ch = gzgetc(stream_);
if (ch == '\n')
file_line_++;
}
while (ch != EOF && !isspace(ch)) {
token.push_back(ch);
ch = gzgetc(stream_);
if (ch == '\n')
file_line_++;
}
if (ch == EOF)
return "";
else
return token;
}
////////////////////////////////////////////////////////////////
static void
reportWaveforms(Vcd &vcd,
Report *report);
void
reportVcdWaveforms(const char *filename,
StaState *sta)
{
Vcd vcd = readVcdFile(filename, sta);
reportWaveforms(vcd, sta->report());
}
static void
reportWaveforms(Vcd &vcd,
Report *report)
{
report->reportLine("Date: %s", vcd.date().c_str());
report->reportLine("Timescale: %.2f%s", vcd.timeScale(), vcd.timeUnit().c_str());
// Characters per time sample.
int zoom = (vcd.maxVarWidth() + 7) / 4;
int time_delta = vcd.minDeltaTime();
int max_var_name_length = vcd.maxVarNameLength();
for (VcdVar &var : vcd.vars()) {
string line;
stringPrint(line, " %-*s",
static_cast<int>(max_var_name_length),
var.name().c_str());
const VcdValues &var_values = vcd.values(var);
if (!var_values.empty()) {
size_t value_index = 0;
VcdValue var_value = var_values[value_index];
VcdValue prev_var_value = var_values[value_index];
VarTime next_value_time = var_values[value_index + 1].time();
for (double time = 0.0; time < vcd.timeMax(); time += time_delta) {
if (time >= next_value_time) {
if (value_index < var_values.size() - 1)
value_index++;
var_value = var_values[value_index];
if (value_index < var_values.size())
next_value_time = var_values[value_index + 1].time();
}
if (var_value.value()) {
// 01UZX
char value = var_value.value();
char prev_value = prev_var_value.value();
if (var.width() == 1) {
if (value == '0' || value == '1') {
for (int z = 0; z < zoom; z++) {
if (z == 0
&& value != prev_value
&& (prev_value == '0'
|| prev_value == '1'))
line += (prev_value == '1') ? "" : "";
else
line += (value == '1') ? "" : "";
}
}
else {
string field;
stringPrint(field, "%-*c", zoom, value);
line += field;
}
}
else {
string field;
stringPrint(field, "%-*c", zoom, value);
line += field;
}
}
else {
// bus
string field;
stringPrint(field, "%-*llX", zoom, var_value.busValue());
line += field;
}
prev_var_value = var_value;
}
}
report->reportLineString(line);
}
}
}

33
power/VcdReader.hh Normal file
View File

@ -0,0 +1,33 @@
// 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
#include "Vcd.hh"
namespace sta {
class StaState;
Vcd
readVcdFile(const char *filename,
StaState *sta);
void
reportVcdWaveforms(const char *filename,
StaState *sta);
}

View File

@ -30,7 +30,7 @@
#include "PathEnd.hh"
#include "PathExpanded.hh"
#include "PathRef.hh"
#include "Power.hh"
#include "power/Power.hh"
#include "Sta.hh"
namespace sta {

View File

@ -68,7 +68,7 @@
#include "VisitPathGroupVertices.hh"
#include "Genclks.hh"
#include "ClkNetwork.hh"
#include "Power.hh"
#include "power/Power.hh"
#include "VisitPathEnds.hh"
#include "PathExpanded.hh"
#include "MakeTimingModel.hh"

View File

@ -79,7 +79,6 @@
#include "search/CheckMinPulseWidths.hh"
#include "search/Levelize.hh"
#include "search/ReportPath.hh"
#include "search/Power.hh"
namespace sta {
@ -4946,69 +4945,6 @@ report_capacitance_limit_verbose(Pin *pin,
////////////////////////////////////////////////////////////////
TmpFloatSeq *
design_power(const Corner *corner)
{
cmdLinkedNetwork();
PowerResult total, sequential, combinational, macro, pad;
Sta::sta()->power(corner, total, sequential, combinational, macro, pad);
FloatSeq *floats = new FloatSeq;
pushPowerResultFloats(total, floats);
pushPowerResultFloats(sequential, floats);
pushPowerResultFloats(combinational, floats);
pushPowerResultFloats(macro, floats);
pushPowerResultFloats(pad, floats);
return floats;
}
TmpFloatSeq *
instance_power(Instance *inst,
const Corner *corner)
{
cmdLinkedNetwork();
PowerResult power;
Sta::sta()->power(inst, corner, power);
FloatSeq *floats = new FloatSeq;
floats->push_back(power.internal());
floats->push_back(power.switching());
floats->push_back(power.leakage());
floats->push_back(power.total());
return floats;
}
void
set_power_global_activity(float activity,
float duty)
{
Sta::sta()->power()->setGlobalActivity(activity, duty);
}
void
set_power_input_activity(float activity,
float duty)
{
return Sta::sta()->power()->setInputActivity(activity, duty);
}
void
set_power_input_port_activity(const Port *input_port,
float activity,
float duty)
{
return Sta::sta()->power()->setInputPortActivity(input_port, activity, duty);
}
void
set_power_pin_activity(const Pin *pin,
float activity,
float duty)
{
return Sta::sta()->power()->setUserActivity(pin, activity, duty,
PwrActivityOrigin::user);
}
////////////////////////////////////////////////////////////////
EdgeSeq *
disabled_edges_sorted()
{