// OpenSTA, Static Timing Analyzer // Copyright (c) 2026, 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 . // // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. // // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // This notice may not be removed or altered from any source distribution. #include "InternalPower.hh" #include #include "FuncExpr.hh" #include "TableModel.hh" #include "Liberty.hh" #include "Units.hh" namespace sta { InternalPower::InternalPower(LibertyPort *port, LibertyPort *related_port, LibertyPort *related_pg_pin, const std::shared_ptr &when, InternalPowerModels &models) : port_(port), related_port_(related_port), related_pg_pin_(related_pg_pin), when_(when), models_(models) { } LibertyCell * InternalPower::libertyCell() const { return port_->libertyCell(); } float InternalPower::power(const RiseFall *rf, const Pvt *pvt, float in_slew, float load_cap) const { const std::shared_ptr &model = models_[rf->index()]; if (model) return model->power(libertyCell(), pvt, in_slew, load_cap); else return 0.0; } const InternalPowerModel * InternalPower::model(const RiseFall *rf) const { const std::shared_ptr &m = models_[rf->index()]; return m.get(); } //////////////////////////////////////////////////////////////// InternalPowerModel::InternalPowerModel(TableModel *model) : model_(model) { } InternalPowerModel::~InternalPowerModel() { delete model_; } float InternalPowerModel::power(const LibertyCell *cell, const Pvt *pvt, float in_slew, float load_cap) const { if (model_) { float axis_value1, axis_value2, axis_value3; findAxisValues(in_slew, load_cap, axis_value1, axis_value2, axis_value3); return model_->findValue(cell, pvt, axis_value1, axis_value2, axis_value3); } else return 0.0; } std::string InternalPowerModel::reportPower(const LibertyCell *cell, const Pvt *pvt, float in_slew, float load_cap, int digits) const { if (model_) { float axis_value1, axis_value2, axis_value3; findAxisValues(in_slew, load_cap, axis_value1, axis_value2, axis_value3); const LibertyLibrary *library = cell->libertyLibrary(); return model_->reportValue("Power", cell, pvt, axis_value1, nullptr, axis_value2, axis_value3, library->units()->powerUnit(), digits); } return ""; } void InternalPowerModel::findAxisValues(float in_slew, float load_cap, // Return values. float &axis_value1, float &axis_value2, float &axis_value3) const { switch (model_->order()) { case 0: axis_value1 = 0.0; axis_value2 = 0.0; axis_value3 = 0.0; break; case 1: axis_value1 = axisValue(model_->axis1(), in_slew, load_cap); axis_value2 = 0.0; axis_value3 = 0.0; break; case 2: axis_value1 = axisValue(model_->axis1(), in_slew, load_cap); axis_value2 = axisValue(model_->axis2(), in_slew, load_cap); axis_value3 = 0.0; break; case 3: axis_value1 = axisValue(model_->axis1(), in_slew, load_cap); axis_value2 = axisValue(model_->axis2(), in_slew, load_cap); axis_value3 = axisValue(model_->axis3(), in_slew, load_cap); break; default: axis_value1 = 0.0; axis_value2 = 0.0; axis_value3 = 0.0; criticalError(225, "unsupported table order"); } } float InternalPowerModel::axisValue(const TableAxis *axis, float in_slew, float load_cap) const { TableAxisVariable var = axis->variable(); if (var == TableAxisVariable::input_transition_time) return in_slew; else if (var == TableAxisVariable::total_output_net_capacitance) return load_cap; else { criticalError(226, "unsupported table axes"); return 0.0; } } bool InternalPowerModel::checkAxes(const TableModel *model) { const TableAxis *axis1 = model->axis1(); const TableAxis *axis2 = model->axis2(); const TableAxis *axis3 = model->axis3(); bool axis_ok = true; if (axis1) axis_ok &= checkAxis(model->axis1()); if (axis2) axis_ok &= checkAxis(model->axis2()); axis_ok &= (axis3 == nullptr); return axis_ok; } bool InternalPowerModel::checkAxis(const TableAxis *axis) { TableAxisVariable var = axis->variable(); return var == TableAxisVariable::constrained_pin_transition || var == TableAxisVariable::related_pin_transition || var == TableAxisVariable::related_out_total_output_net_capacitance; } } // namespace