read_vcd_activities
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
commit
cecb8cda7e
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -23,3 +23,4 @@
|
|||
%include "Sdf.i"
|
||||
%include "DelayCalc.i"
|
||||
%include "Parasitics.i"
|
||||
%include "Power.i"
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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] {
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
64
tcl/StaTcl.i
64
tcl/StaTcl.i
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue