power use cofactor activity for internal power

This commit is contained in:
James Cherry 2020-05-02 16:12:25 -07:00
parent 60eaa584d4
commit bb4ceacd4d
2 changed files with 73 additions and 125 deletions

View File

@ -155,19 +155,18 @@ protected:
BfsFwdIterator &bfs); BfsFwdIterator &bfs);
PwrActivity evalActivity(FuncExpr *expr, PwrActivity evalActivity(FuncExpr *expr,
const Instance *inst); const Instance *inst);
bool internalPowerMissingWhen(LibertyCell *cell, PwrActivity evalActivity(FuncExpr *expr,
const LibertyPort *to_port, const Instance *inst,
const char *related_pg_pin); const LibertyPort *cofactor_port,
FuncExpr *inferedWhen(FuncExpr *expr, bool cofactor_positive);
const LibertyPort *port);
LibertyPort *findExprOutPort(FuncExpr *expr); LibertyPort *findExprOutPort(FuncExpr *expr);
void findInputDuty(const Pin *to_pin, float findInputDuty(const Pin *to_pin,
const Instance *inst, const Instance *inst,
FuncExpr *func, FuncExpr *func,
InternalPower *pwr, InternalPower *pwr);
// Return values. PwrActivity evalActivityDifference(FuncExpr *expr,
float &duty, const Instance *inst,
FuncExpr *&infered_when); const LibertyPort *cofactor_port);
private: private:
PwrActivity global_activity_; PwrActivity global_activity_;

View File

@ -59,8 +59,6 @@
namespace sta { namespace sta {
static int
funcExprPortCount(FuncExpr *expr);
static bool static bool
isPositiveUnate(const LibertyCell *cell, isPositiveUnate(const LibertyCell *cell,
const LibertyPort *from, const LibertyPort *from,
@ -338,24 +336,45 @@ PropActivityVisitor::visit(Vertex *vertex)
PwrActivity PwrActivity
Power::evalActivity(FuncExpr *expr, Power::evalActivity(FuncExpr *expr,
const Instance *inst) const Instance *inst)
{
return evalActivity(expr, inst, nullptr, true);
}
// Eval activity thru expr.
// With cofactor_port eval the positive/negative cofactor of expr wrt cofactor_port.
PwrActivity
Power::evalActivity(FuncExpr *expr,
const Instance *inst,
const LibertyPort *cofactor_port,
bool cofactor_positive)
{ {
switch (expr->op()) { switch (expr->op()) {
case FuncExpr::op_port: { case FuncExpr::op_port: {
Pin *pin = network_->findPin(inst, expr->port()->name()); LibertyPort *port = expr->port();
if (port == cofactor_port) {
if (cofactor_positive)
return PwrActivity(0.0, 1.0, PwrActivityOrigin::constant);
else
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
}
Pin *pin = network_->findPin(inst, port->name());
if (pin) if (pin)
return findActivity(pin); return findActivity(pin);
else else
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant); return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
} }
case FuncExpr::op_not: { case FuncExpr::op_not: {
PwrActivity activity1 = evalActivity(expr->left(), inst); PwrActivity activity1 = evalActivity(expr->left(), inst,
cofactor_port, cofactor_positive);
return PwrActivity(activity1.activity(), return PwrActivity(activity1.activity(),
1.0 - activity1.duty(), 1.0 - activity1.duty(),
PwrActivityOrigin::propagated); PwrActivityOrigin::propagated);
} }
case FuncExpr::op_or: { case FuncExpr::op_or: {
PwrActivity activity1 = evalActivity(expr->left(), inst); PwrActivity activity1 = evalActivity(expr->left(), inst,
PwrActivity activity2 = evalActivity(expr->right(), inst); cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float p1 = 1.0 - activity1.duty(); float p1 = 1.0 - activity1.duty();
float p2 = 1.0 - activity2.duty(); float p2 = 1.0 - activity2.duty();
return PwrActivity(activity1.activity() * p2 return PwrActivity(activity1.activity() * p2
@ -364,8 +383,10 @@ Power::evalActivity(FuncExpr *expr,
PwrActivityOrigin::propagated); PwrActivityOrigin::propagated);
} }
case FuncExpr::op_and: { case FuncExpr::op_and: {
PwrActivity activity1 = evalActivity(expr->left(), inst); PwrActivity activity1 = evalActivity(expr->left(), inst,
PwrActivity activity2 = evalActivity(expr->right(), inst); cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float p1 = activity1.duty(); float p1 = activity1.duty();
float p2 = activity2.duty(); float p2 = activity2.duty();
return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1, return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1,
@ -373,8 +394,10 @@ Power::evalActivity(FuncExpr *expr,
PwrActivityOrigin::propagated); PwrActivityOrigin::propagated);
} }
case FuncExpr::op_xor: { case FuncExpr::op_xor: {
PwrActivity activity1 = evalActivity(expr->left(), inst); PwrActivity activity1 = evalActivity(expr->left(), inst,
PwrActivity activity2 = evalActivity(expr->right(), inst); cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float p1 = activity1.duty() * (1.0 - activity2.duty()); float p1 = activity1.duty() * (1.0 - activity2.duty());
float p2 = activity2.duty() * (1.0 - activity1.duty()); float p2 = activity2.duty() * (1.0 - activity1.duty());
return PwrActivity(activity1.activity() * p1 + activity2.activity() * p2, return PwrActivity(activity1.activity() * p1 + activity2.activity() * p2,
@ -587,12 +610,8 @@ Power::findInputInternalPower(const Pin *pin,
LibertyPort *out_port = findExprOutPort(when); LibertyPort *out_port = findExprOutPort(when);
if (out_port) { if (out_port) {
FuncExpr *func = out_port->function(); FuncExpr *func = out_port->function();
// eval cofactor of func wrt input if (func->hasPort(port))
FuncExpr *sensitize_expr = inferedWhen(func, port); duty = evalActivityDifference(func, inst, port).duty();
if (sensitize_expr) {
duty = evalActivity(sensitize_expr, inst).duty();
sensitize_expr->deleteSubexprs();
}
else else
duty = evalActivity(when, inst).duty(); duty = evalActivity(when, inst).duty();
} }
@ -645,6 +664,21 @@ Power::findExprOutPort(FuncExpr *expr)
} }
} }
PwrActivity
Power::evalActivityDifference(FuncExpr *expr,
const Instance *inst,
const LibertyPort *cofactor_port)
{
PwrActivity pos = evalActivity(expr, inst, cofactor_port, true);
PwrActivity neg = evalActivity(expr, inst, cofactor_port, false);
// difference(expr) wrt cofactor port = xor(pos, neg).
float p1 = pos.duty() * (1.0 - neg.duty());
float p2 = neg.duty() * (1.0 - pos.duty());
return PwrActivity(pos.activity() * p1 + neg.activity() * p2,
p1 + p2,
PwrActivityOrigin::propagated);
}
void void
Power::findOutputInternalPower(const Pin *to_pin, Power::findOutputInternalPower(const Pin *to_pin,
const LibertyPort *to_port, const LibertyPort *to_port,
@ -667,24 +701,16 @@ Power::findOutputInternalPower(const Pin *to_pin,
map<const char*, float, StringLessIf> pg_duty_sum; map<const char*, float, StringLessIf> pg_duty_sum;
for (InternalPower *pwr : *cell->internalPowers(to_port)) { for (InternalPower *pwr : *cell->internalPowers(to_port)) {
float duty; float duty = findInputDuty(to_pin, inst, func, pwr);
FuncExpr *infered_when;
findInputDuty(to_pin, inst, func, pwr,
duty, infered_when);
const char *related_pg_pin = pwr->relatedPgPin(); const char *related_pg_pin = pwr->relatedPgPin();
pg_duty_sum[related_pg_pin] += duty; pg_duty_sum[related_pg_pin] += duty;
if (infered_when)
infered_when->deleteSubexprs();
} }
float internal = 0.0; float internal = 0.0;
for (InternalPower *pwr : *cell->internalPowers(to_port)) { for (InternalPower *pwr : *cell->internalPowers(to_port)) {
FuncExpr *when = pwr->when(); FuncExpr *when = pwr->when();
const char *related_pg_pin = pwr->relatedPgPin(); const char *related_pg_pin = pwr->relatedPgPin();
float duty; float duty = findInputDuty(to_pin, inst, func, pwr);
FuncExpr *infered_when;
findInputDuty(to_pin, inst, func, pwr,
duty, infered_when);
const LibertyPort *from_port = pwr->relatedPort(); const LibertyPort *from_port = pwr->relatedPort();
const Pin *from_pin = network_->findPin(inst, from_port); const Pin *from_pin = network_->findPin(inst, from_port);
Vertex *from_vertex = graph_->pinLoadVertex(from_pin); Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
@ -711,7 +737,7 @@ Power::findOutputInternalPower(const Pin *to_pin,
debugPrint9(debug_, "power", 2, "%3s -> %-3s %6s %.2f %.2f %.2f %9.2e %9.2e %s\n", debugPrint9(debug_, "power", 2, "%3s -> %-3s %6s %.2f %.2f %.2f %9.2e %9.2e %s\n",
from_port->name(), from_port->name(),
to_port->name(), to_port->name(),
when ? when->asString() : (infered_when ? infered_when->asString() : ""), when ? when->asString() : "",
to_activity.activity() * 1e-9, to_activity.activity() * 1e-9,
duty, duty,
weight, weight,
@ -719,44 +745,36 @@ Power::findOutputInternalPower(const Pin *to_pin,
port_internal, port_internal,
related_pg_pin ? related_pg_pin : "no pg_pin"); related_pg_pin ? related_pg_pin : "no pg_pin");
internal += port_internal; internal += port_internal;
if (infered_when)
infered_when->deleteSubexprs();
} }
result.internal() += internal; result.internal() += internal;
} }
void float
Power::findInputDuty(const Pin *to_pin, Power::findInputDuty(const Pin *to_pin,
const Instance *inst, const Instance *inst,
FuncExpr *func, FuncExpr *func,
InternalPower *pwr, InternalPower *pwr)
// Return values.
float &duty,
FuncExpr *&infered_when)
{ {
const char *related_pg_pin = pwr->relatedPgPin(); const char *related_pg_pin = pwr->relatedPgPin();
const LibertyPort *from_port = pwr->relatedPort(); const LibertyPort *from_port = pwr->relatedPort();
FuncExpr *when = pwr->when(); FuncExpr *when = pwr->when();
infered_when = (when == nullptr && func)
? inferedWhen(func, from_port)
: nullptr;
const Pin *from_pin = network_->findPin(inst, from_port); const Pin *from_pin = network_->findPin(inst, from_port);
Vertex *from_vertex = graph_->pinLoadVertex(from_pin); Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
duty = 0.5; if (func->hasPort(from_port)) {
if (infered_when) {
PwrActivity from_activity = findActivity(from_pin); PwrActivity from_activity = findActivity(from_pin);
PwrActivity to_activity = findActivity(to_pin); PwrActivity to_activity = findActivity(to_pin);
float duty1 = evalActivity(infered_when, inst).duty(); float duty1 = evalActivityDifference(func, inst, from_port).duty();
if (to_activity.activity() == 0.0) if (to_activity.activity() == 0.0)
duty = 0.0; return 0.0;
else else
duty = from_activity.activity() / to_activity.activity() * duty1; return from_activity.activity() / to_activity.activity() * duty1;
} }
else if (when) else if (when)
duty = evalActivity(when, inst).duty(); return evalActivity(when, inst).duty();
else if (search_->isClock(from_vertex)) else if (search_->isClock(from_vertex))
duty = 1.0; return 1.0;
return 0.5;
} }
static bool static bool
@ -796,77 +814,8 @@ negate(FuncExpr *expr)
return FuncExpr::makeNot(expr->copy()); return FuncExpr::makeNot(expr->copy());
} }
// Positive shannon cofactor of expr wrt port.
FuncExpr *
Power::inferedWhen(FuncExpr *expr,
const LibertyPort *port)
{
switch (expr->op()) {
case FuncExpr::op_port: {
if (expr->port() == port)
return FuncExpr::makeOne();
else
return nullptr;
}
case FuncExpr::op_not:
return inferedWhen(expr->left(), port);
case FuncExpr::op_or:
case FuncExpr::op_xor: {
if (isPortRef(expr->left(), port))
return negate(expr->right());
if (isPortRef(expr->right(), port))
return negate(expr->left());
break;
}
case FuncExpr::op_and: {
if (isPortRef(expr->left(), port))
return expr->right()->copy();
if (isPortRef(expr->right(), port))
return expr->left()->copy();
break;
}
case FuncExpr::op_one:
case FuncExpr::op_zero:
return expr;
}
return nullptr;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Return true if some a "when" clause for the internal power to_port
// is missing.
bool
Power::internalPowerMissingWhen(LibertyCell *cell,
const LibertyPort *to_port,
const char *related_pg_pin)
{
int when_input_count = 0;
int when_count = 0;
for (InternalPower *pwr : *cell->internalPowers(to_port)) {
auto when = pwr->when();
if (pwr->relatedPort() == nullptr
&& stringEqIf(pwr->relatedPgPin(), related_pg_pin)
&& when) {
when_count++;
when_input_count = funcExprPortCount(when);
}
}
return when_count != (1 << when_input_count);
}
static int
funcExprPortCount(FuncExpr *expr)
{
int port_count = 0;
FuncExprPortIterator port_iter(expr);
while (port_iter.hasNext()) {
port_iter.next();
port_count++;
}
return port_count;
}
void void
Power::findLeakagePower(const Instance *, Power::findLeakagePower(const Instance *,
LibertyCell *cell, LibertyCell *cell,