2.0.15
This commit is contained in:
parent
30974b0604
commit
d1a602cefc
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
cmake_minimum_required (VERSION 3.9)
|
||||
|
||||
project(STA VERSION 2.0.14)
|
||||
project(STA VERSION 2.0.15)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
|
|
|||
|
|
@ -9,18 +9,36 @@ Release 2.0.0 2018/09/28
|
|||
Builds using Autotools/configure are no longer supported.
|
||||
Use CMake as documented in README.mb.
|
||||
|
||||
....
|
||||
|
||||
The check_timing command -no_output_delay checks output ports for
|
||||
set_output_delay.
|
||||
|
||||
....
|
||||
|
||||
The report_power command reports the power consumption of the design
|
||||
or a specific instance.
|
||||
|
||||
report_power [-instance inst] [-digits digits] [> filename] [>> filename]
|
||||
report_power [-instances inst] [-digits digits] [> filename] [>> filename]
|
||||
|
||||
Report power used by the design or a specific instance. The internal,
|
||||
switching, leakage and total power are reported. Design power is
|
||||
reported separately for combinational, sequential, macro and pad
|
||||
groups.
|
||||
The internal, switching, leakage and total power are reported. Design
|
||||
power is reported separately for combinational, sequential, macro and
|
||||
pad groups.
|
||||
|
||||
Use -instances to report power for a specific instance.
|
||||
|
||||
Use the set_power_activity command to specify activity/duty
|
||||
globally using -global, the input port default using -input,
|
||||
or for input ports using -input_ports, or pins using -pins.
|
||||
|
||||
set_power_activity [-global]
|
||||
[-input]
|
||||
[-input_ports ports]
|
||||
[-pins pins]
|
||||
[-activiity activity]
|
||||
[-duty duty]
|
||||
|
||||
....
|
||||
|
||||
The write_path_spice command writes a spice netlist for a timing path.
|
||||
|
||||
|
|
@ -46,6 +64,8 @@ and ground names are specified with the -power and -ground arguments.
|
|||
The spice netlist includes a piecewise linear voltage source at the
|
||||
input and .measure statement for each gate delay and pin slew.
|
||||
|
||||
....
|
||||
|
||||
The report_checks, find_timing_paths commands now support an
|
||||
-unconstrained flag.
|
||||
|
||||
|
|
@ -55,6 +75,8 @@ The report_checks, find_timing_paths commands now support an
|
|||
The sta_report_unconstrained_paths variable will be supported for
|
||||
for compatibility in this current release.
|
||||
|
||||
....
|
||||
|
||||
The read_parasitics command has been renamed read_spef and no longer
|
||||
supports the SPF format.
|
||||
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -20,7 +20,7 @@
|
|||
#define STA_DELAY_H
|
||||
|
||||
#if (SSTA == 1)
|
||||
// Delays are Normal PDFs with early/late sigma.
|
||||
// Delays are Normal PDFs.
|
||||
#include "DelayNormal1.hh"
|
||||
#elif (SSTA == 2)
|
||||
// Delays are Normal PDFs with early/late sigma.
|
||||
|
|
|
|||
|
|
@ -52,20 +52,20 @@ delayInitValue(const MinMax *min_max)
|
|||
|
||||
Delay::Delay() :
|
||||
mean_(0.0),
|
||||
sigma2_{0.0}
|
||||
sigma2_(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
Delay::Delay(float mean) :
|
||||
mean_(mean),
|
||||
sigma2_{0.0}
|
||||
sigma2_(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
Delay::Delay(float mean,
|
||||
float sigma2) :
|
||||
mean_(mean),
|
||||
sigma2_{sigma2}
|
||||
sigma2_(sigma2)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ void
|
|||
Delay::operator-=(const Delay &delay)
|
||||
{
|
||||
mean_ -= delay.mean_;
|
||||
sigma2_ -= delay.sigma2_;
|
||||
sigma2_ += delay.sigma2_;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -348,11 +348,10 @@ operator/(float delay1,
|
|||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float scale)
|
||||
float delay2)
|
||||
{
|
||||
float scale2 = square(scale);
|
||||
return Delay(delay1.mean() * scale,
|
||||
delay1.sigma2() * scale2);
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2() * delay2);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ void
|
|||
Delay::operator-=(const Delay &delay)
|
||||
{
|
||||
mean_ -= delay.mean_;
|
||||
sigma2_[early_index] -= delay.sigma2_[early_index];
|
||||
sigma2_[late_index] -= delay.sigma2_[late_index];
|
||||
sigma2_[early_index] += delay.sigma2_[early_index];
|
||||
sigma2_[late_index] += delay.sigma2_[late_index];
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -374,12 +374,11 @@ operator/(float delay1,
|
|||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float scale)
|
||||
float delay2)
|
||||
{
|
||||
float scale2 = square(scale);
|
||||
return Delay(delay1.mean() * scale,
|
||||
delay1.sigma2Early() * scale2,
|
||||
delay1.sigma2Late() * scale2);
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2()Early * delay2,
|
||||
delay1.sigma2Late() * delay2);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
|
|||
|
|
@ -878,9 +878,6 @@ LibertyCell::~LibertyCell()
|
|||
pg_port_map_.deleteContents();
|
||||
}
|
||||
|
||||
// Multiple timing arc sets (buses bits or a related_ports list)
|
||||
// can share the same TimingAttrs values (model, cond, and sdf_conds),
|
||||
// so collect them into a set so they are only deleted once.
|
||||
void
|
||||
LibertyCell::deleteTimingArcAttrs()
|
||||
{
|
||||
|
|
@ -1176,6 +1173,7 @@ LibertyCell::makeTimingArcMap(Report *)
|
|||
// match->from()->name(),
|
||||
// match->to()->name(),
|
||||
// match->role()->asString());
|
||||
delete arc_set;
|
||||
}
|
||||
else
|
||||
// Shift arc sets down to fill holes left by removed duplicates.
|
||||
|
|
|
|||
519
search/Power.cc
519
search/Power.cc
|
|
@ -17,23 +17,30 @@
|
|||
#include <algorithm> // max
|
||||
#include "Machine.hh"
|
||||
#include "Debug.hh"
|
||||
#include "EnumNameMap.hh"
|
||||
#include "Units.hh"
|
||||
#include "Transition.hh"
|
||||
#include "MinMax.hh"
|
||||
#include "Clock.hh"
|
||||
#include "TimingRole.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "InternalPower.hh"
|
||||
#include "LeakagePower.hh"
|
||||
#include "Sequential.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "FuncExpr.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Network.hh"
|
||||
#include "Graph.hh"
|
||||
#include "Sim.hh"
|
||||
#include "Corner.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "PathVertex.hh"
|
||||
#include "Clock.hh"
|
||||
#include "Levelize.hh"
|
||||
#include "Sim.hh"
|
||||
#include "Search.hh"
|
||||
#include "Bfs.hh"
|
||||
#include "Power.hh"
|
||||
|
||||
// Related liberty not supported:
|
||||
|
|
@ -54,23 +61,65 @@ typedef Map<const char*, SumCount, CharPtrLess> SupplySumCounts;
|
|||
|
||||
Power::Power(Sta *sta) :
|
||||
StaState(sta),
|
||||
sta_(sta),
|
||||
default_signal_toggle_rate_(.1)
|
||||
global_activity_{0.0, 0.0, PwrActivityOrigin::unknown},
|
||||
input_activity_{0.1, 0.5, PwrActivityOrigin::input},
|
||||
default_activity_(.1),
|
||||
activities_valid_(false)
|
||||
{
|
||||
}
|
||||
|
||||
float
|
||||
Power::defaultSignalToggleRate()
|
||||
{
|
||||
return default_signal_toggle_rate_;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setDefaultSignalToggleRate(float rate)
|
||||
Power::setGlobalActivity(float activity,
|
||||
float duty)
|
||||
{
|
||||
default_signal_toggle_rate_ = rate;
|
||||
global_activity_.set(activity, duty, PwrActivityOrigin::global);
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setInputActivity(float activity,
|
||||
float duty)
|
||||
{
|
||||
input_activity_.set(activity, duty, PwrActivityOrigin::input);
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setInputPortActivity(const Port *input_port,
|
||||
float activity,
|
||||
float duty)
|
||||
{
|
||||
Instance *top_inst = network_->topInstance();
|
||||
const Pin *pin = network_->findPin(top_inst, input_port);
|
||||
if (pin) {
|
||||
activity_map_[pin] = {activity, duty, PwrActivityOrigin::user};
|
||||
activities_valid_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
PwrActivity &
|
||||
Power::pinActivity(const Pin *pin)
|
||||
{
|
||||
return activity_map_[pin];
|
||||
}
|
||||
|
||||
void
|
||||
Power::setPinActivity(const Pin *pin,
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
{
|
||||
activity_map_[pin] = {activity, duty, origin};
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setPinActivity(const Pin *pin,
|
||||
PwrActivity &activity)
|
||||
{
|
||||
activity_map_[pin] = activity;
|
||||
activities_valid_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
Power::power(const Corner *corner,
|
||||
|
|
@ -86,6 +135,8 @@ Power::power(const Corner *corner,
|
|||
combinational.clear();
|
||||
macro.clear();
|
||||
pad.clear();
|
||||
|
||||
preamble();
|
||||
LeafInstanceIterator *inst_iter = network_->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
|
|
@ -107,8 +158,6 @@ Power::power(const Corner *corner,
|
|||
delete inst_iter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Power::power(const Instance *inst,
|
||||
const Corner *corner,
|
||||
|
|
@ -116,10 +165,268 @@ Power::power(const Instance *inst,
|
|||
PowerResult &result)
|
||||
{
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
if (cell)
|
||||
if (cell) {
|
||||
preamble();
|
||||
power(inst, cell, corner, result);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class ActivitySrchPred : public SearchPred
|
||||
{
|
||||
public:
|
||||
explicit ActivitySrchPred(const StaState *sta);
|
||||
virtual bool searchFrom(const Vertex *from_vertex);
|
||||
virtual bool searchThru(Edge *edge);
|
||||
virtual bool searchTo(const Vertex *);
|
||||
|
||||
protected:
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
ActivitySrchPred::ActivitySrchPred(const StaState *sta) :
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ActivitySrchPred::searchFrom(const Vertex *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ActivitySrchPred::searchThru(Edge *edge)
|
||||
{
|
||||
auto role = edge->role();
|
||||
return !(edge->isDisabledLoop()
|
||||
|| role->isTimingCheck()
|
||||
|| role == TimingRole::regClkToQ());
|
||||
}
|
||||
|
||||
bool
|
||||
ActivitySrchPred::searchTo(const Vertex *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class PropActivityVisitor : public VertexVisitor, StaState
|
||||
{
|
||||
public:
|
||||
PropActivityVisitor(Power *power,
|
||||
BfsFwdIterator *bfs);
|
||||
virtual VertexVisitor *copy();
|
||||
virtual void visit(Vertex *vertex);
|
||||
|
||||
private:
|
||||
Power *power_;
|
||||
BfsFwdIterator *bfs_;
|
||||
};
|
||||
|
||||
PropActivityVisitor::PropActivityVisitor(Power *power,
|
||||
BfsFwdIterator *bfs) :
|
||||
StaState(power),
|
||||
power_(power),
|
||||
bfs_(bfs)
|
||||
{
|
||||
}
|
||||
|
||||
VertexVisitor *
|
||||
PropActivityVisitor::copy()
|
||||
{
|
||||
return new PropActivityVisitor(power_, bfs_);
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::evalActivity(FuncExpr *expr,
|
||||
const Instance *inst)
|
||||
{
|
||||
switch (expr->op()) {
|
||||
case FuncExpr::op_port: {
|
||||
Pin *pin = network_->findPin(inst, expr->port()->name());
|
||||
if (pin)
|
||||
return pinActivity(pin);
|
||||
}
|
||||
case FuncExpr::op_not: {
|
||||
PwrActivity activity1 = evalActivity(expr->left(), inst);
|
||||
return PwrActivity(activity1.activity(),
|
||||
1.0 - activity1.duty(),
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
case FuncExpr::op_or: {
|
||||
PwrActivity activity1 = evalActivity(expr->left(), inst);
|
||||
PwrActivity activity2 = evalActivity(expr->right(), inst);
|
||||
float p1 = 1.0 - activity1.duty();
|
||||
float p2 = 1.0 - activity2.duty();
|
||||
return PwrActivity(activity1.activity() * p2
|
||||
+ activity2.activity() * p1,
|
||||
1.0 - p1 * p2,
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
case FuncExpr::op_and: {
|
||||
PwrActivity activity1 = evalActivity(expr->left(), inst);
|
||||
PwrActivity activity2 = evalActivity(expr->right(), inst);
|
||||
float p1 = activity1.duty();
|
||||
float p2 = activity2.duty();
|
||||
return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1,
|
||||
p1 * p2,
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
case FuncExpr::op_xor: {
|
||||
PwrActivity activity1 = evalActivity(expr->left(), inst);
|
||||
PwrActivity activity2 = evalActivity(expr->right(), inst);
|
||||
float p1 = activity1.duty() * (1.0 - activity2.duty());
|
||||
float p2 = activity2.duty() * (1.0 - activity1.duty());
|
||||
return PwrActivity(activity1.activity() * p1 + activity2.activity() * p2,
|
||||
p1 + p2,
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
case FuncExpr::op_one:
|
||||
return PwrActivity(0.0, 1.0, PwrActivityOrigin::constant);
|
||||
case FuncExpr::op_zero:
|
||||
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
|
||||
}
|
||||
return PwrActivity();
|
||||
}
|
||||
|
||||
void
|
||||
PropActivityVisitor::visit(Vertex *vertex)
|
||||
{
|
||||
auto pin = vertex->pin();
|
||||
debugPrint1(debug_, "power", 3, "activity %s\n",
|
||||
vertex->name(network_));
|
||||
if (network_->isLoad(pin)) {
|
||||
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||
if (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
if (edge->isWire()) {
|
||||
Vertex *from_vertex = edge->from(graph_);
|
||||
const Pin *from_pin = from_vertex->pin();
|
||||
PwrActivity &from_activity = power_->pinActivity(from_pin);
|
||||
PwrActivity to_activity(from_activity.activity(),
|
||||
from_activity.duty(),
|
||||
PwrActivityOrigin::propagated);
|
||||
power_->setPinActivity(pin, to_activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (network_->isDriver(pin)) {
|
||||
LibertyPort *port = network_->libertyPort(pin);
|
||||
if (port) {
|
||||
FuncExpr *func = port->function();
|
||||
Instance *inst = network_->instance(pin);
|
||||
PwrActivity activity = power_->evalActivity(func, inst);
|
||||
power_->setPinActivity(pin, activity);
|
||||
}
|
||||
}
|
||||
bfs_->enqueueAdjacentVertices(vertex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Power::preamble()
|
||||
{
|
||||
ensureActivities();
|
||||
}
|
||||
|
||||
void
|
||||
Power::ensureActivities()
|
||||
{
|
||||
if (!global_activity_.isSet()) {
|
||||
if (!activities_valid_) {
|
||||
ActivitySrchPred activity_srch_pred(this);
|
||||
BfsFwdIterator bfs(BfsIndex::other, &activity_srch_pred, this);
|
||||
seedActivities(bfs);
|
||||
PropActivityVisitor visitor(this, &bfs);
|
||||
bfs.visit(levelize_->maxLevel(), &visitor);
|
||||
// Propagate activiities across register D->Q.
|
||||
seedRegOutputActivities(bfs);
|
||||
bfs.visit(levelize_->maxLevel(), &visitor);
|
||||
activities_valid_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Power::seedActivities(BfsFwdIterator &bfs)
|
||||
{
|
||||
Instance *top_inst = network_->topInstance();
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(top_inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *pin = pin_iter->next();
|
||||
if (network_->direction(pin)->isAnyInput()) {
|
||||
// Clock activities are baked in.
|
||||
if (!sdc_->isClock(pin)) {
|
||||
PwrActivity &activity = pinActivity(pin);
|
||||
PwrActivityOrigin origin = activity.origin();
|
||||
// Default inputs without explicit activities to the input default.
|
||||
if (origin != PwrActivityOrigin::user)
|
||||
setPinActivity(pin, input_activity_);
|
||||
Vertex *vertex = graph_->pinDrvrVertex(pin);
|
||||
bfs.enqueueAdjacentVertices(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
void
|
||||
Power::seedRegOutputActivities(BfsFwdIterator &bfs)
|
||||
{
|
||||
LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator();
|
||||
while (leaf_iter->hasNext()) {
|
||||
auto inst = leaf_iter->next();
|
||||
auto cell = network_->libertyCell(inst);
|
||||
if (cell) {
|
||||
LibertyCellSequentialIterator seq_iter(cell);
|
||||
while (seq_iter.hasNext()) {
|
||||
Sequential *seq = seq_iter.next();
|
||||
seedRegOutputActivities(inst, seq, seq->output(), false);
|
||||
seedRegOutputActivities(inst, seq, seq->outputInv(), true);
|
||||
// Enqueue register output pins with functions that reference
|
||||
// the sequential internal pins (IQ, IQN).
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
auto pin = pin_iter->next();
|
||||
auto port = network_->libertyPort(pin);
|
||||
auto func = port->function();
|
||||
if (func) {
|
||||
Vertex *vertex = graph_->pinDrvrVertex(pin);
|
||||
if (func->port() == seq->output()
|
||||
|| func->port() == seq->outputInv())
|
||||
bfs.enqueue(vertex);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete leaf_iter;
|
||||
}
|
||||
|
||||
void
|
||||
Power::seedRegOutputActivities(Instance *reg,
|
||||
Sequential *seq,
|
||||
LibertyPort *output,
|
||||
bool invert)
|
||||
{
|
||||
const Pin *pin = network_->findPin(reg, output);
|
||||
if (pin) {
|
||||
PwrActivity activity = evalActivity(seq->data(), reg);
|
||||
if (invert)
|
||||
activity.set(activity.activity(),
|
||||
1.0 - activity.duty(),
|
||||
activity.origin());
|
||||
setPinActivity(pin, activity);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Power::power(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
|
|
@ -137,13 +444,11 @@ Power::power(const Instance *inst,
|
|||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, TransRiseFall::rise(), dcalc_ap)
|
||||
: 0.0;
|
||||
float activity1;
|
||||
bool is_clk;
|
||||
activity(to_pin, inst_clk, activity1, is_clk);
|
||||
PwrActivity activity = findActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput())
|
||||
findSwitchingPower(cell, to_port, activity1, load_cap,
|
||||
findSwitchingPower(cell, to_port, activity, load_cap,
|
||||
dcalc_ap, result);
|
||||
findInternalPower(inst, cell, to_port, activity1,
|
||||
findInternalPower(inst, cell, to_port, activity,
|
||||
load_cap, dcalc_ap, result);
|
||||
}
|
||||
delete pin_iter;
|
||||
|
|
@ -157,10 +462,8 @@ Power::findInstClk(const Instance *inst)
|
|||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *pin = pin_iter->next();
|
||||
const Clock *clk = nullptr;
|
||||
bool is_clk;
|
||||
findClk(pin, clk, is_clk);
|
||||
if (is_clk)
|
||||
const Clock *clk = findClk(pin);
|
||||
if (clk)
|
||||
inst_clk = clk;
|
||||
}
|
||||
delete pin_iter;
|
||||
|
|
@ -171,7 +474,7 @@ void
|
|||
Power::findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
|
|
@ -183,10 +486,9 @@ Power::findInternalPower(const Instance *inst,
|
|||
cell->name());
|
||||
SupplySumCounts supply_sum_counts;
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
float duty = 1.0;
|
||||
debugPrint2(debug_, "power", 2, " cap = %s duty = %.1f\n",
|
||||
units_->capacitanceUnit()->asString(load_cap),
|
||||
duty);
|
||||
debugPrint1(debug_, "power", 2, " cap = %s\n",
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
debugPrint0(debug_, "power", 2, " when act/ns duty energy power\n");
|
||||
LibertyCellInternalPowerIterator pwr_iter(cell);
|
||||
while (pwr_iter.hasNext()) {
|
||||
InternalPower *pwr = pwr_iter.next();
|
||||
|
|
@ -197,33 +499,37 @@ Power::findInternalPower(const Instance *inst,
|
|||
from_port = to_port;
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
FuncExpr *when = pwr->when();
|
||||
PwrActivity when_activity = when ? evalActivity(when, inst)
|
||||
: findActivity(from_pin);
|
||||
float duty = when_activity.duty();
|
||||
float port_energy = 0.0;
|
||||
float port_internal = 0.0;
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *to_tr = tr_iter.next();
|
||||
// Should use unateness to find from_tr.
|
||||
TransRiseFall *from_tr = to_tr;
|
||||
float slew = delayAsFloat(sta_->vertexSlew(from_vertex,
|
||||
from_tr, dcalc_ap));
|
||||
float energy;
|
||||
if (from_port)
|
||||
energy = pwr->power(to_tr, pvt, slew, load_cap);
|
||||
else
|
||||
energy = pwr->power(to_tr, pvt, 0.0, 0.0);
|
||||
float tr_internal = energy * activity * duty;
|
||||
float slew = delayAsFloat(graph_->slew(from_vertex,
|
||||
from_tr,
|
||||
dcalc_ap->index()));
|
||||
float tr_energy = (from_port)
|
||||
? pwr->power(to_tr, pvt, slew, load_cap)
|
||||
: pwr->power(to_tr, pvt, 0.0, 0.0);
|
||||
float tr_internal = tr_energy * activity.activity();
|
||||
port_energy += tr_energy;
|
||||
port_internal += tr_internal;
|
||||
debugPrint5(debug_, "power", 2, " %s -> %s %s %s (%s)\n",
|
||||
from_port->name(),
|
||||
to_tr->shortName(),
|
||||
to_port->name(),
|
||||
pwr->when() ? pwr->when()->asString() : "",
|
||||
related_pg_pin ? related_pg_pin : "(no pg_pin)");
|
||||
debugPrint4(debug_, "power", 2, " slew = %s activity = %.2f/ns energy = %.5g pwr = %.5g\n",
|
||||
units_->timeUnit()->asString(slew),
|
||||
activity * 1e-9,
|
||||
energy,
|
||||
tr_internal);
|
||||
}
|
||||
debugPrint8(debug_, "power", 2, " %s -> %s %s %.2f %.2f %9.2e %9.2e %s\n",
|
||||
from_port->name(),
|
||||
to_port->name(),
|
||||
pwr->when() ? pwr->when()->asString() : " ",
|
||||
activity.activity() * 1e-9,
|
||||
duty,
|
||||
port_energy,
|
||||
port_internal,
|
||||
related_pg_pin ? related_pg_pin : "no pg_pin");
|
||||
|
||||
// Sum/count internal power arcs by supply to average across conditions.
|
||||
SumCount &supply_sum_count = supply_sum_counts[related_pg_pin];
|
||||
// Average rise/fall internal power.
|
||||
|
|
@ -239,7 +545,9 @@ Power::findInternalPower(const Instance *inst,
|
|||
internal += supply_internal / (supply_count > 0 ? supply_count : 1);
|
||||
}
|
||||
|
||||
debugPrint1(debug_, "power", 2, " internal = %.5g\n", internal);
|
||||
debugPrint2(debug_, "power", 2, " %s internal = %.3e\n",
|
||||
to_port->name(),
|
||||
internal);
|
||||
result.setInternal(result.internal() + internal);
|
||||
}
|
||||
|
||||
|
|
@ -303,43 +611,62 @@ Power::findLeakagePower(const Instance *,
|
|||
void
|
||||
Power::findSwitchingPower(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
float volt = voltage(cell, to_port, dcalc_ap);
|
||||
float switching = .5 * load_cap * volt * volt * activity;
|
||||
float switching = .5 * load_cap * volt * volt * activity.activity();
|
||||
debugPrint5(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e\n",
|
||||
cell->name(),
|
||||
to_port->name(),
|
||||
activity,
|
||||
activity.activity(),
|
||||
volt,
|
||||
switching);
|
||||
volt = voltage(cell, to_port, dcalc_ap);
|
||||
result.setSwitching(result.switching() + switching);
|
||||
}
|
||||
|
||||
void
|
||||
Power::activity(const Pin *pin,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
float &activity,
|
||||
bool &is_clk)
|
||||
PwrActivity
|
||||
Power::findActivity(const Pin *pin)
|
||||
{
|
||||
const Clock *clk = inst_clk;
|
||||
findClk(pin, clk, is_clk);
|
||||
activity = 0.0;
|
||||
const Instance *inst = network_->instance(pin);
|
||||
const Clock *inst_clk = findInstClk(inst);
|
||||
return findActivity(pin, inst_clk);
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findActivity(const Pin *pin,
|
||||
const Clock *inst_clk)
|
||||
{
|
||||
const Clock *clk = findClk(pin);
|
||||
if (clk == nullptr)
|
||||
clk = inst_clk;
|
||||
if (clk) {
|
||||
float period = clk->period();
|
||||
if (period > 0.0) {
|
||||
if (is_clk)
|
||||
activity = 2.0 / period;
|
||||
else
|
||||
activity = default_signal_toggle_rate_ / period;
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
if (search_->isClock(vertex))
|
||||
return PwrActivity(2.0 / period, 0.5, PwrActivityOrigin::clock);
|
||||
else if (global_activity_.isSet())
|
||||
return PwrActivity(global_activity_.activity() / period,
|
||||
0.5, PwrActivityOrigin::global);
|
||||
else {
|
||||
if (activity_map_.hasKey(pin)) {
|
||||
PwrActivity &activity = activity_map_[pin];
|
||||
if (activity.origin() != PwrActivityOrigin::unknown)
|
||||
return PwrActivity(activity.activity() / period,
|
||||
activity.duty(),
|
||||
activity.origin());
|
||||
}
|
||||
return PwrActivity(default_activity_ / period,
|
||||
0.5, PwrActivityOrigin::defaulted);
|
||||
}
|
||||
}
|
||||
}
|
||||
return PwrActivity();
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -370,13 +697,10 @@ Power::voltage(LibertyCell *cell,
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findClk(const Pin *to_pin,
|
||||
// Return values.
|
||||
const Clock *&clk,
|
||||
bool &is_clk)
|
||||
const Clock *
|
||||
Power::findClk(const Pin *to_pin)
|
||||
{
|
||||
is_clk = false;
|
||||
const Clock *clk = nullptr;
|
||||
Vertex *to_vertex = graph_->pinDrvrVertex(to_pin);
|
||||
VertexPathIterator path_iter(to_vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
|
|
@ -386,9 +710,8 @@ Power::findClk(const Pin *to_pin,
|
|||
&& (clk == nullptr
|
||||
|| path_clk->period() < clk->period()))
|
||||
clk = path_clk;
|
||||
if (path->isClock(this))
|
||||
is_clk = true;
|
||||
}
|
||||
return clk;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -440,4 +763,54 @@ PowerResult::incr(PowerResult &result)
|
|||
leakage_ += result.leakage_;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
static EnumNameMap<PwrActivityOrigin> pwr_activity_origin_map =
|
||||
{{PwrActivityOrigin::global, "global"},
|
||||
{PwrActivityOrigin::input, "input"},
|
||||
{PwrActivityOrigin::user, "user"},
|
||||
{PwrActivityOrigin::propagated, "propagated"},
|
||||
{PwrActivityOrigin::clock, "clock"},
|
||||
{PwrActivityOrigin::constant, "constant"},
|
||||
{PwrActivityOrigin::defaulted, "defaulted"},
|
||||
{PwrActivityOrigin::unknown, "unknown"}};
|
||||
|
||||
PwrActivity::PwrActivity(float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin) :
|
||||
activity_(activity),
|
||||
duty_(duty),
|
||||
origin_(origin)
|
||||
{
|
||||
}
|
||||
|
||||
PwrActivity::PwrActivity() :
|
||||
activity_(0.0),
|
||||
duty_(0.0),
|
||||
origin_(PwrActivityOrigin::unknown)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PwrActivity::set(float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
{
|
||||
activity_ = activity;
|
||||
duty_ = duty;
|
||||
origin_ = origin;
|
||||
}
|
||||
|
||||
bool
|
||||
PwrActivity::isSet() const
|
||||
{
|
||||
return origin_ != PwrActivityOrigin::unknown;
|
||||
}
|
||||
|
||||
const char *
|
||||
PwrActivity::originName() const
|
||||
{
|
||||
return pwr_activity_origin_map.find(origin_);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -22,6 +22,46 @@
|
|||
namespace sta {
|
||||
|
||||
class PowerResult;
|
||||
class PwrActivity;
|
||||
class PropActivityVisitor;
|
||||
class BfsFwdIterator;
|
||||
|
||||
typedef UnorderedMap<const Pin*,PwrActivity> PwrActivityMap;
|
||||
|
||||
enum class PwrActivityOrigin
|
||||
{
|
||||
global,
|
||||
input,
|
||||
user,
|
||||
propagated,
|
||||
clock,
|
||||
constant,
|
||||
defaulted, // temporary
|
||||
unknown
|
||||
};
|
||||
|
||||
class PwrActivity
|
||||
{
|
||||
public:
|
||||
PwrActivity();
|
||||
PwrActivity(float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin);
|
||||
float activity() const { return activity_; }
|
||||
float duty() const { return duty_; }
|
||||
PwrActivityOrigin origin() { return origin_; }
|
||||
const char *originName() const;
|
||||
void set(float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin);
|
||||
bool isSet() const;
|
||||
|
||||
private:
|
||||
// In general activity is per clock cycle, NOT per second.
|
||||
float activity_;
|
||||
float duty_;
|
||||
PwrActivityOrigin origin_;
|
||||
};
|
||||
|
||||
// The Power class has access to Sta components directly for
|
||||
// convenience but also requires access to the Sta class member functions.
|
||||
|
|
@ -40,10 +80,27 @@ public:
|
|||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
float defaultSignalToggleRate();
|
||||
void setDefaultSignalToggleRate(float rate);
|
||||
void setGlobalActivity(float activity,
|
||||
float duty);
|
||||
void setInputActivity(float activity,
|
||||
float duty);
|
||||
void setInputPortActivity(const Port *input_port,
|
||||
float activity,
|
||||
float duty);
|
||||
PwrActivity &pinActivity(const Pin *pin);
|
||||
void setPinActivity(const Pin *pin,
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin);
|
||||
void setPinActivity(const Pin *pin,
|
||||
PwrActivity &activity);
|
||||
// Activity is toggles per second.
|
||||
PwrActivity findActivity(const Pin *pin);
|
||||
|
||||
protected:
|
||||
void preamble();
|
||||
void ensureActivities();
|
||||
|
||||
void power(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
|
|
@ -52,7 +109,7 @@ protected:
|
|||
void findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
|
|
@ -63,28 +120,35 @@ protected:
|
|||
PowerResult &result);
|
||||
void findSwitchingPower(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
const Clock *findInstClk(const Instance *inst);
|
||||
void findClk(const Pin *to_pin,
|
||||
// Return values.
|
||||
const Clock *&clk,
|
||||
bool &is_clk);
|
||||
void activity(const Pin *pin,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
float &activity,
|
||||
bool &is_clk);
|
||||
const Clock *findClk(const Pin *to_pin);
|
||||
PwrActivity findActivity(const Pin *pin,
|
||||
const Clock *inst_clk);
|
||||
float voltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
void seedActivities(BfsFwdIterator &bfs);
|
||||
void seedRegOutputActivities(BfsFwdIterator &bfs);
|
||||
void seedRegOutputActivities(Instance *reg,
|
||||
Sequential *seq,
|
||||
LibertyPort *output,
|
||||
bool invert);
|
||||
PwrActivity evalActivity(FuncExpr *expr,
|
||||
const Instance *inst);
|
||||
|
||||
private:
|
||||
Sta *sta_;
|
||||
float default_signal_toggle_rate_;
|
||||
PwrActivity global_activity_;
|
||||
PwrActivity input_activity_;
|
||||
float default_activity_;
|
||||
PwrActivityMap activity_map_;
|
||||
bool activities_valid_;
|
||||
|
||||
friend class PropActivityVisitor;
|
||||
};
|
||||
|
||||
class PowerResult
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "PathEnd.hh"
|
||||
#include "PathExpanded.hh"
|
||||
#include "PathRef.hh"
|
||||
#include "Property.hh"
|
||||
#include "Power.hh"
|
||||
#include "Sta.hh"
|
||||
#include "Property.hh"
|
||||
|
||||
|
|
@ -208,6 +208,12 @@ PropertyValue::PropertyValue(PathRefSeq *value) :
|
|||
{
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(PwrActivity *value) :
|
||||
type_(type_pwr_activity),
|
||||
pwr_activity_(*value)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(const PropertyValue &value) :
|
||||
type_(value.type_)
|
||||
{
|
||||
|
|
@ -253,6 +259,9 @@ PropertyValue::PropertyValue(const PropertyValue &value) :
|
|||
case Type::type_path_refs:
|
||||
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
||||
break;
|
||||
case Type::type_pwr_activity:
|
||||
pwr_activity_ = value.pwr_activity_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -299,12 +308,17 @@ PropertyValue::PropertyValue(PropertyValue &&value) :
|
|||
break;
|
||||
case Type::type_clks:
|
||||
clks_ = value.clks_;
|
||||
// Steal the value.
|
||||
value.clks_ = nullptr;
|
||||
break;
|
||||
case Type::type_path_refs:
|
||||
path_refs_ = value.path_refs_;
|
||||
// Steal the value.
|
||||
value.clks_ = nullptr;
|
||||
break;
|
||||
case Type::type_pwr_activity:
|
||||
pwr_activity_ = value.pwr_activity_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,6 +388,9 @@ PropertyValue::operator=(const PropertyValue &value)
|
|||
case Type::type_path_refs:
|
||||
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
||||
break;
|
||||
case Type::type_pwr_activity:
|
||||
pwr_activity_ = value.pwr_activity_;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -428,6 +445,9 @@ PropertyValue::operator=(PropertyValue &&value)
|
|||
path_refs_ = value.path_refs_;
|
||||
value.clks_ = nullptr;
|
||||
break;
|
||||
case Type::type_pwr_activity:
|
||||
pwr_activity_ = value.pwr_activity_;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -534,6 +554,12 @@ getProperty(const Port *port,
|
|||
return PropertyValue(network->name(port));
|
||||
else if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(port)->name());
|
||||
else if (stringEqual(property, "activity")) {
|
||||
const Instance *top_inst = network->topInstance();
|
||||
const Pin *pin = network->findPin(top_inst, port);
|
||||
PwrActivity activity = sta->power()->findActivity(pin);
|
||||
return PropertyValue(&activity);
|
||||
}
|
||||
|
||||
else if (stringEqual(property, "actual_fall_transition_min"))
|
||||
return portSlewProperty(port, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
|
|
@ -637,6 +663,10 @@ getProperty(const Pin *pin,
|
|||
sta->clocks(pin, clks);
|
||||
return PropertyValue(&clks);
|
||||
}
|
||||
else if (stringEqual(property, "activity")) {
|
||||
PwrActivity activity = sta->power()->findActivity(pin);
|
||||
return PropertyValue(&activity);
|
||||
}
|
||||
|
||||
else if (stringEqual(property, "max_fall_slack"))
|
||||
return pinSlackProperty(pin, TransRiseFall::fall(), MinMax::max(), sta);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace sta {
|
|||
using std::string;
|
||||
|
||||
class Sta;
|
||||
class PwrActivity;
|
||||
|
||||
class PropertyValue
|
||||
{
|
||||
|
|
@ -36,7 +37,7 @@ public:
|
|||
type_liberty_library, type_liberty_cell,
|
||||
type_library, type_cell,
|
||||
type_instance, type_pin, type_pins, type_net,
|
||||
type_clk, type_clks, type_path_refs };
|
||||
type_clk, type_clks, type_path_refs, type_pwr_activity };
|
||||
PropertyValue();
|
||||
PropertyValue(const char *value);
|
||||
PropertyValue(string &value);
|
||||
|
|
@ -54,6 +55,7 @@ public:
|
|||
PropertyValue(ClockSeq *value);
|
||||
PropertyValue(ClockSet *value);
|
||||
PropertyValue(PathRefSeq *value);
|
||||
PropertyValue(PwrActivity *value);
|
||||
// Copy constructor.
|
||||
PropertyValue(const PropertyValue &props);
|
||||
// Move constructor.
|
||||
|
|
@ -73,6 +75,7 @@ public:
|
|||
Clock *clock() const { return clk_; }
|
||||
ClockSeq *clocks() const { return clks_; }
|
||||
PathRefSeq *pathRefs() const { return path_refs_; }
|
||||
PwrActivity pwrActivity() const { return pwr_activity_; }
|
||||
// Copy assignment.
|
||||
PropertyValue &operator=(const PropertyValue &);
|
||||
// Move assignment.
|
||||
|
|
@ -94,6 +97,7 @@ private:
|
|||
Clock *clk_;
|
||||
ClockSeq *clks_;
|
||||
PathRefSeq *path_refs_;
|
||||
PwrActivity pwr_activity_;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ proc_redirect report_power {
|
|||
|
||||
parse_key_args "report_power" args keys {-instances -corner -digits} flags {} 1
|
||||
|
||||
if [info exists keys(-digits)] {
|
||||
if { [info exists keys(-digits)] } {
|
||||
set digits $keys(-digits)
|
||||
check_positive_integer "-digits" $digits
|
||||
} else {
|
||||
|
|
@ -191,22 +191,55 @@ proc report_power_inst { inst power_result field_width digits } {
|
|||
|
||||
################################################################
|
||||
|
||||
set ::power_default_signal_toggle_rate 0.1
|
||||
define_cmd_args "set_power_activity" { [-global]\
|
||||
[-input]\
|
||||
[-input_ports ports]\
|
||||
[-pins pins]\
|
||||
[-activiity activity]\
|
||||
[-duty duty] }
|
||||
|
||||
trace variable ::power_default_signal_toggle_rate "rw" \
|
||||
sta::trace_power_default_signal_toggle_rate
|
||||
proc set_power_activity { args } {
|
||||
parse_key_args "set_power_activity" args \
|
||||
keys {-input_ports -pins -activity -duty} \
|
||||
flags {-global -input} 1
|
||||
|
||||
proc trace_power_default_signal_toggle_rate { name1 name2 op } {
|
||||
global power_default_signal_toggle_rate
|
||||
set activity 0.0
|
||||
if { [info exists keys(-activity)] } {
|
||||
set activity $keys(-activity)
|
||||
check_float "activity" $activity
|
||||
if { $activity < 0.0 } {
|
||||
sta_warn "activity should be 0.0 to 1.0 or 2.0"
|
||||
}
|
||||
}
|
||||
set duty 0.5
|
||||
if { [info exists keys(-duty)] } {
|
||||
set duty $keys(-duty)
|
||||
check_float "duty" $duty
|
||||
if { $duty < 0.0 || $duty > 1.0 } {
|
||||
sta_warn "duty should be 0.0 to 1.0"
|
||||
}
|
||||
}
|
||||
|
||||
if { $op == "r" } {
|
||||
set power_default_signal_toggle_rate [power_default_signal_toggle_rate]
|
||||
} elseif { $op == "w" } {
|
||||
if { [string is double $power_default_signal_toggle_rate] \
|
||||
&& $power_default_signal_toggle_rate >= 0.0 } {
|
||||
set_power_default_signal_toggle_rate $power_default_signal_toggle_rate
|
||||
} else {
|
||||
sta_error "power_default_signal_toggle_rate must be a positive float."
|
||||
if { [info exists flags(-global)] } {
|
||||
set_power_global_activity $activity $duty
|
||||
}
|
||||
if { [info exists flags(-input)] } {
|
||||
set_power_input_activity $activity $duty
|
||||
}
|
||||
if { [info exists keys(-input_ports)] } {
|
||||
set ports [get_ports_error "input_ports" $keys(-input_ports)]
|
||||
foreach port $ports {
|
||||
if { [get_property $port "direction"] == "input" } {
|
||||
set_power_input_port_activity $port $activity $duty
|
||||
}
|
||||
}
|
||||
}
|
||||
if { [info exists keys(-pins)] } {
|
||||
set ports [get_pins_error "pins" $keys(-pins)]
|
||||
foreach pin $pins {
|
||||
if { [get_property $pin "direction"] == "input" } {
|
||||
set_power_pin_activity $pin $activity $duty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
tcl/StaTcl.i
50
tcl/StaTcl.i
|
|
@ -1619,6 +1619,27 @@ using namespace sta;
|
|||
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
}
|
||||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
break;
|
||||
case PropertyValue::Type::type_pwr_activity: {
|
||||
PwrActivity activity = value.pwrActivity();
|
||||
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
||||
Tcl_Obj *obj;
|
||||
const char *str;
|
||||
|
||||
str = stringPrintTmp("%.5e", activity.activity());
|
||||
obj = Tcl_NewStringObj(str, strlen(str));
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
|
||||
str = stringPrintTmp("%.3f", activity.duty());
|
||||
obj = Tcl_NewStringObj(str, strlen(str));
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
|
||||
str = activity.originName();
|
||||
obj = Tcl_NewStringObj(str, strlen(str));
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
|
||||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
break;
|
||||
|
|
@ -4670,16 +4691,35 @@ instance_power(Instance *inst,
|
|||
return floats;
|
||||
}
|
||||
|
||||
float
|
||||
power_default_signal_toggle_rate()
|
||||
void
|
||||
set_power_global_activity(float activity,
|
||||
float duty)
|
||||
{
|
||||
return Sta::sta()->power()->defaultSignalToggleRate();
|
||||
Sta::sta()->power()->setGlobalActivity(activity, duty);
|
||||
}
|
||||
|
||||
void
|
||||
set_power_default_signal_toggle_rate(float rate)
|
||||
set_power_input_activity(float activity,
|
||||
float duty)
|
||||
{
|
||||
return Sta::sta()->power()->setDefaultSignalToggleRate(rate);
|
||||
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()->setPinActivity(pin, activity, duty,
|
||||
PwrActivityOrigin::user);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
Loading…
Reference in New Issue