issue138 power w/gated clock feedback loops

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-03-06 16:20:58 -07:00
parent 6ad97c7562
commit 1e53cc3b5a
1 changed files with 46 additions and 65 deletions

View File

@ -299,16 +299,15 @@ class PropActivityVisitor : public VertexVisitor, StaState
public:
PropActivityVisitor(Power *power,
BfsFwdIterator *bfs);
~PropActivityVisitor();
virtual VertexVisitor *copy() const;
virtual void visit(Vertex *vertex);
void init();
bool foundRegWithoutActivity() const;
InstanceSet *stealVisitedRegs();
InstanceSet &visitedRegs() { return visited_regs_; }
private:
InstanceSet *visited_regs_;
bool found_reg_without_activity_;
bool setActivityCheck(const Pin *pin,
PwrActivity &activity);
InstanceSet visited_regs_;
Power *power_;
BfsFwdIterator *bfs_;
};
@ -316,44 +315,18 @@ private:
PropActivityVisitor::PropActivityVisitor(Power *power,
BfsFwdIterator *bfs) :
StaState(power),
visited_regs_(nullptr),
visited_regs_(network_),
power_(power),
bfs_(bfs)
{
}
PropActivityVisitor::~PropActivityVisitor()
{
delete visited_regs_;
}
VertexVisitor *
PropActivityVisitor::copy() const
{
return new PropActivityVisitor(power_, bfs_);
}
void
PropActivityVisitor::init()
{
visited_regs_ = new InstanceSet(network_);
found_reg_without_activity_ = false;
}
InstanceSet *
PropActivityVisitor::stealVisitedRegs()
{
InstanceSet *visited_regs = visited_regs_;
visited_regs_ = nullptr;
return visited_regs;
}
bool
PropActivityVisitor::foundRegWithoutActivity() const
{
return found_reg_without_activity_;
}
void
PropActivityVisitor::visit(Vertex *vertex)
{
@ -361,16 +334,14 @@ PropActivityVisitor::visit(Vertex *vertex)
Instance *inst = network_->instance(pin);
debugPrint(debug_, "power_activity", 3, "visit %s",
vertex->name(network_));
bool input_without_activity = false;
bool changed = false;
if (power_->hasUserActivity(pin)) {
PwrActivity &activity = power_->userActivity(pin);
debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f",
vertex->name(network_),
activity.activity(),
activity.duty());
if (!power_->hasActivity(pin))
input_without_activity = true;
power_->setActivity(pin, activity);
changed = setActivityCheck(pin, activity);
}
else {
if (network_->isLoad(pin)) {
@ -384,9 +355,7 @@ PropActivityVisitor::visit(Vertex *vertex)
PwrActivity to_activity(from_activity.activity(),
from_activity.duty(),
PwrActivityOrigin::propagated);
if (!power_->hasActivity(pin))
input_without_activity = true;
power_->setActivity(pin, to_activity);
changed = setActivityCheck(pin, to_activity);
}
}
}
@ -395,9 +364,8 @@ PropActivityVisitor::visit(Vertex *vertex)
if (port) {
FuncExpr *func = port->function();
if (func) {
Instance *inst = network_->instance(pin);
PwrActivity activity = power_->evalActivity(func, inst);
power_->setActivity(pin, activity);
changed = setActivityCheck(pin, activity);
debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f",
vertex->name(network_),
activity.activity(),
@ -414,7 +382,7 @@ PropActivityVisitor::visit(Vertex *vertex)
PwrActivity activity(activity1.activity() * p2 + activity2.activity() * p1,
p1 * p2,
PwrActivityOrigin::propagated);
power_->setActivity(gclk, activity);
changed = setActivityCheck(gclk, activity);
debugPrint(debug_, "power_activity", 3, "gated_clk %s %.2e %.2f",
network_->pathName(gclk),
activity.activity(),
@ -424,25 +392,41 @@ PropActivityVisitor::visit(Vertex *vertex)
}
}
}
LibertyCell *cell = network_->libertyCell(inst);
if (network_->isLoad(pin) && cell) {
if (cell->hasSequentials()) {
debugPrint(debug_, "power_activity", 3, "pending seq %s",
network_->pathName(inst));
visited_regs_->insert(inst);
found_reg_without_activity_ |= input_without_activity;
}
// Gated clock cells latch the enable so there is no EN->GCLK timing arc.
if (cell->isClockGate()) {
const Pin *enable, *clk, *gclk;
power_->clockGatePins(inst, enable, clk, gclk);
if (gclk) {
Vertex *gclk_vertex = graph_->pinDrvrVertex(gclk);
bfs_->enqueue(gclk_vertex);
if (changed) {
LibertyCell *cell = network_->libertyCell(inst);
if (network_->isLoad(pin) && cell) {
if (cell->hasSequentials()) {
debugPrint(debug_, "power_activity", 3, "pending seq %s",
network_->pathName(inst));
visited_regs_.insert(inst);
}
// Gated clock cells latch the enable so there is no EN->GCLK timing arc.
if (cell->isClockGate()) {
const Pin *enable, *clk, *gclk;
power_->clockGatePins(inst, enable, clk, gclk);
if (gclk) {
Vertex *gclk_vertex = graph_->pinDrvrVertex(gclk);
bfs_->enqueue(gclk_vertex);
}
}
}
bfs_->enqueueAdjacentVertices(vertex);
}
bfs_->enqueueAdjacentVertices(vertex);
}
// Return true if the activity changed.
bool
PropActivityVisitor::setActivityCheck(const Pin *pin,
PwrActivity &activity)
{
PwrActivity &prev_activity = power_->activity(pin);
if (abs(activity.activity() - prev_activity.activity()) > .001
|| abs(activity.duty() - prev_activity.duty()) > .001) {
power_->setActivity(pin, activity);
return true;
}
else
return false;
}
void
@ -568,24 +552,21 @@ Power::ensureActivities()
BfsFwdIterator bfs(BfsIndex::other, &activity_srch_pred, this);
seedActivities(bfs);
PropActivityVisitor visitor(this, &bfs);
visitor.init();
// Propagate activities through combinational logic.
bfs.visit(levelize_->maxLevel(), &visitor);
// Propagate activiities through registers.
while (visitor.foundRegWithoutActivity()) {
InstanceSet *regs = visitor.stealVisitedRegs();
InstanceSet regs = std::move(visitor.visitedRegs());
while (!regs.empty()) {
InstanceSet::Iterator reg_iter(regs);
while (reg_iter.hasNext()) {
const Instance *reg = reg_iter.next();
// Propagate activiities across register D->Q.
seedRegOutputActivities(reg, bfs);
}
delete regs;
visitor.init();
// Propagate register output activities through
// combinational logic.
bfs.visit(levelize_->maxLevel(), &visitor);
regs = std::move(visitor.visitedRegs());
}
activities_valid_ = true;
}