diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 548879f8..af4df1f2 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index ea9aca4c..547636d4 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/examples/power.tcl b/examples/power.tcl index b515f109..51b616c1 100644 --- a/examples/power.tcl +++ b/examples/power.tcl @@ -4,6 +4,7 @@ read_verilog gcd_sky130hd.v link_design gcd read_sdc gcd_sky130hd.sdc +set_propagated_clock clk read_spef gcd_sky130hd.spef set_power_activity -input -activity .1 set_power_activity -input_port reset -activity 0 diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 718aa880..998ca562 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -1282,6 +1282,7 @@ public: PowerResult &total, PowerResult &sequential, PowerResult &combinational, + PowerResult &clock, PowerResult ¯o, PowerResult &pad); PowerResult power(const Instance *inst, diff --git a/power/Power.cc b/power/Power.cc index 92ea3ca6..2a516f17 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -202,12 +202,14 @@ Power::power(const Corner *corner, PowerResult &total, PowerResult &sequential, PowerResult &combinational, + PowerResult &clock, PowerResult ¯o, PowerResult &pad) { total.clear(); sequential.clear(); combinational.clear(); + clock.clear(); macro.clear(); pad.clear(); @@ -226,6 +228,8 @@ Power::power(const Corner *corner, pad.incr(inst_power); else if (cell->hasSequentials()) sequential.incr(inst_power); + else if (inClockNetwork(inst)) + clock.incr(inst_power); else combinational.incr(inst_power); total.incr(inst_power); @@ -234,6 +238,22 @@ Power::power(const Corner *corner, delete inst_iter; } +bool +Power::inClockNetwork(const Instance *inst) +{ + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + if (network_->direction(pin)->isAnyOutput() + && !clk_network_->isClock(pin)) { + delete pin_iter; + return false; + } + } + delete pin_iter; + return true; +} + PowerResult Power::power(const Instance *inst, const Corner *corner) @@ -363,7 +383,7 @@ PropActivityVisitor::visit(Vertex *vertex) Edge *edge = edge_iter.next(); if (edge->isWire()) { Vertex *from_vertex = edge->from(graph_); - const Pin *from_pin = from_vertex->pin(); + const Pin *from_pin = from_vertex->pin(); PwrActivity &from_activity = power_->activity(from_pin); PwrActivity to_activity(from_activity.activity(), from_activity.duty(), @@ -436,7 +456,8 @@ PropActivityVisitor::setActivityCheck(const Pin *pin, float activity_delta = abs(activity.activity() - prev_activity.activity()); float duty_delta = abs(activity.duty() - prev_activity.duty()); if (activity_delta > change_tolerance_ - || duty_delta > change_tolerance_) { + || duty_delta > change_tolerance_ + || activity.origin() != prev_activity.origin()) { max_change_ = max(max_change_, activity_delta); max_change_ = max(max_change_, duty_delta); power_->setActivity(pin, activity); @@ -1016,7 +1037,7 @@ isPositiveUnate(const LibertyCell *cell, //////////////////////////////////////////////////////////////// void -Power::findLeakagePower(const Instance *, +Power::findLeakagePower(const Instance *inst, LibertyCell *cell, const Corner *corner, // Return values. @@ -1031,21 +1052,16 @@ Power::findLeakagePower(const Instance *, for (LeakagePower *leak : *corner_cell->leakagePowers()) { FuncExpr *when = leak->when(); if (when) { - FuncExprPortIterator port_iter(when); - float duty = 1.0; - while (port_iter.hasNext()) { - LibertyPort *port = port_iter.next(); - if (port->direction()->isAnyInput()) - duty *= port->isClock() ? 0.25 : 0.5; - } + PwrActivity cond_activity = evalActivity(when, inst); + float cond_duty = cond_activity.duty(); debugPrint(debug_, "power", 2, "leakage %s %s %.3e * %.2f", cell->name(), when->asString(), leak->power(), - duty); - cond_leakage += leak->power() * duty; + cond_duty); + cond_leakage += leak->power() * cond_duty; if (leak->power() > 0.0) - cond_duty_sum += duty; + cond_duty_sum += cond_duty; found_cond = true; } else { @@ -1152,7 +1168,7 @@ Power::findActivity(const Pin *pin) if (activity.origin() != PwrActivityOrigin::unknown) return activity; } - return input_activity_; + return PwrActivity(0.0, 0.0, PwrActivityOrigin::unknown); } PwrActivity diff --git a/power/Power.hh b/power/Power.hh index 3cc5a1b3..0359d486 100644 --- a/power/Power.hh +++ b/power/Power.hh @@ -67,6 +67,7 @@ public: PowerResult &total, PowerResult &sequential, PowerResult &combinational, + PowerResult &clock, PowerResult ¯o, PowerResult &pad); PowerResult power(const Instance *inst, @@ -87,6 +88,7 @@ public: PwrActivity findClkedActivity(const Pin *pin); protected: + bool inClockNetwork(const Instance *inst); void powerInside(const Instance *hinst, const Corner *corner, PowerResult &result); diff --git a/power/Power.i b/power/Power.i index 19c2d545..962d7313 100644 --- a/power/Power.i +++ b/power/Power.i @@ -43,12 +43,13 @@ FloatSeq design_power(const Corner *corner) { cmdLinkedNetwork(); - PowerResult total, sequential, combinational, macro, pad; - Sta::sta()->power(corner, total, sequential, combinational, macro, pad); + PowerResult total, sequential, combinational, clock, macro, pad; + Sta::sta()->power(corner, total, sequential, combinational, clock, macro, pad); FloatSeq powers; pushPowerResultFloats(total, powers); pushPowerResultFloats(sequential, powers); pushPowerResultFloats(combinational, powers); + pushPowerResultFloats(clock, powers); pushPowerResultFloats(macro, powers); pushPowerResultFloats(pad, powers); return powers; diff --git a/power/Power.tcl b/power/Power.tcl index ec177739..3d2fae13 100644 --- a/power/Power.tcl +++ b/power/Power.tcl @@ -56,8 +56,9 @@ proc report_power_design { corner digits } { set totals [lrange $power_result 0 3] set sequential [lrange $power_result 4 7] set combinational [lrange $power_result 8 11] - set macro [lrange $power_result 12 15] - set pad [lrange $power_result 16 end] + set clock [lrange $power_result 12 15] + set macro [lrange $power_result 16 19] + set pad [lrange $power_result 20 end] lassign $totals design_internal design_switching design_leakage design_total set field_width [max [expr $digits + 6] 10] @@ -66,6 +67,7 @@ proc report_power_design { corner digits } { report_title_dashes5 $field_width report_power_row "Sequential" $sequential $design_total $field_width $digits report_power_row "Combinational" $combinational $design_total $field_width $digits + report_power_row "Clock" $clock $design_total $field_width $digits report_power_row "Macro" $macro $design_total $field_width $digits report_power_row "Pad" $pad $design_total $field_width $digits report_title_dashes5 $field_width diff --git a/power/ReadVcdActivities.cc b/power/ReadVcdActivities.cc index f151d75d..f89b785e 100644 --- a/power/ReadVcdActivities.cc +++ b/power/ReadVcdActivities.cc @@ -99,7 +99,10 @@ ReadVcdActivities::readActivities() for (Clock *clk : *sta_->sdc()->clocks()) clk_period_ = min(static_cast(clk->period()), clk_period_); - setActivities(); + if (vcd_.timeMax() > 0) + setActivities(); + else + report_->warn(808, "VCD max time is zero."); report_->reportLine("Annotated %lu pin activities.", annotated_pins_.size()); } @@ -166,7 +169,7 @@ ReadVcdActivities::setVarActivity(VcdVar *var, } } else - report_->warn(807, "problem parsing bus %s.", var_name.c_str()); + report_->warn(809, "problem parsing bus %s.", var_name.c_str()); } } @@ -175,7 +178,7 @@ ReadVcdActivities::setVarActivity(const char *pin_name, const VcdValues &var_values, int value_bit) { - const Pin *pin = network_->findPin(pin_name); + const Pin *pin = sdc_network_->findPin(pin_name); if (pin) { double transition_count, activity, duty; findVarActivity(var_values, value_bit, diff --git a/search/Sta.cc b/search/Sta.cc index 58dae681..b886db80 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -5700,11 +5700,12 @@ Sta::power(const Corner *corner, PowerResult &total, PowerResult &sequential, PowerResult &combinational, + PowerResult &clock, PowerResult ¯o, PowerResult &pad) { powerPreamble(); - power_->power(corner, total, sequential, combinational, macro, pad); + power_->power(corner, total, sequential, combinational, clock, macro, pad); } PowerResult diff --git a/test/power.ok b/test/power.ok index 6d6e32b2..20b60589 100644 --- a/test/power.ok +++ b/test/power.ok @@ -2,10 +2,11 @@ Warning: gcd_sky130hd.v line 527, module sky130_fd_sc_hd__tapvpwrvgnd_1 not foun Group Internal Switching Leakage Total Power Power Power Power (Watts) ---------------------------------------------------------------- -Sequential 3.39e-04 8.75e-05 2.96e-10 4.27e-04 35.7% -Combinational 3.07e-04 4.63e-04 6.98e-10 7.69e-04 64.3% +Sequential 3.27e-04 7.87e-05 2.96e-10 4.06e-04 36.4% +Combinational 2.34e-04 3.10e-04 6.95e-10 5.43e-04 48.7% +Clock 4.68e-05 1.20e-04 2.30e-11 1.67e-04 15.0% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% ---------------------------------------------------------------- -Total 6.46e-04 5.50e-04 9.94e-10 1.20e-03 100.0% - 54.0% 46.0% 0.0% +Total 6.07e-04 5.09e-04 1.01e-09 1.12e-03 100.0% + 54.4% 45.6% 0.0% diff --git a/test/power_vcd.ok b/test/power_vcd.ok index b29c1110..5744deeb 100644 --- a/test/power_vcd.ok +++ b/test/power_vcd.ok @@ -3,10 +3,11 @@ Annotated 936 pin activities. Group Internal Switching Leakage Total Power Power Power Power (Watts) ---------------------------------------------------------------- -Sequential 3.05e-04 3.84e-05 2.96e-10 3.44e-04 44.6% -Combinational 1.48e-04 2.79e-04 6.98e-10 4.27e-04 55.4% +Sequential 3.05e-04 3.84e-05 2.92e-10 3.44e-04 44.6% +Combinational 9.95e-05 1.59e-04 6.76e-10 2.58e-04 33.5% +Clock 4.82e-05 1.20e-04 2.30e-11 1.69e-04 21.9% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% ---------------------------------------------------------------- -Total 4.53e-04 3.18e-04 9.94e-10 7.71e-04 100.0% +Total 4.53e-04 3.18e-04 9.91e-10 7.71e-04 100.0% 58.8% 41.2% 0.0% diff --git a/util/Report.cc b/util/Report.cc index 3bb881d6..3e040c91 100644 --- a/util/Report.cc +++ b/util/Report.cc @@ -145,12 +145,16 @@ Report::printToBufferAppend(const char *fmt, // Copy args in case we need to grow the buffer. va_list args_copy; va_copy(args_copy, args); - int length = vsnprint(buffer_ + buffer_length_, buffer_size_, fmt, args); - if (buffer_length_ >= buffer_size_) { + size_t length = vsnprint(buffer_ + buffer_length_, buffer_size_- buffer_length_, + fmt, args); + if (length >= buffer_size_) { + buffer_size_ = buffer_length_ + length * 2; + char *new_buffer = new char[buffer_size_]; + strncpy(new_buffer, buffer_, buffer_length_); delete [] buffer_; - buffer_size_ = buffer_length_ * 2; - buffer_ = new char[buffer_size_]; - length = vsnprint(buffer_ + buffer_length_, buffer_size_, fmt, args_copy); + buffer_ = new_buffer; + length = vsnprint(buffer_ + buffer_length_, buffer_size_ - buffer_length_, + fmt, args_copy); } buffer_length_ += length; va_end(args_copy);