OpenSTA/liberty/TableModel.cc

1444 lines
40 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2019-01-01 21:26:11 +01:00
// Copyright (c) 2019, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// 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 <https://www.gnu.org/licenses/>.
#include "Machine.hh"
#include "Report.hh"
#include "Error.hh"
#include "Units.hh"
#include "Liberty.hh"
#include "TableModel.hh"
namespace sta {
2018-11-26 18:15:52 +01:00
static void
reportPvt(const LibertyLibrary *library,
const Pvt *pvt,
int digits,
string *result);
2018-09-28 17:54:21 +02:00
static void
appendSpaces(string *result,
int count);
GateTableModel::GateTableModel(TableModel *delay_model,
2018-11-26 18:15:52 +01:00
TableModel *delay_sigma_models[EarlyLate::index_count],
TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count]) :
2018-09-28 17:54:21 +02:00
delay_model_(delay_model),
slew_model_(slew_model)
{
2018-11-26 18:15:52 +01:00
MinMaxIterator el_iter;
while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next();
int el_index = early_late->index();
slew_sigma_models_[el_index] = slew_sigma_models[el_index];
delay_sigma_models_[el_index] = delay_sigma_models[el_index];
}
2018-09-28 17:54:21 +02:00
}
GateTableModel::~GateTableModel()
{
delete delay_model_;
delete slew_model_;
2018-11-26 18:15:52 +01:00
MinMaxIterator el_iter;
while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next();
int el_index = early_late->index();
delete slew_sigma_models_[el_index];
delete delay_sigma_models_[el_index];
}
2018-09-28 17:54:21 +02:00
}
void
GateTableModel::setIsScaled(bool is_scaled)
{
if (delay_model_)
delay_model_->setIsScaled(is_scaled);
if (slew_model_)
slew_model_->setIsScaled(is_scaled);
}
void
GateTableModel::gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
2019-01-27 08:03:01 +01:00
bool pocv_enabled,
2018-09-28 17:54:21 +02:00
// return values
2018-11-26 18:15:52 +01:00
ArcDelay &gate_delay,
Slew &drvr_slew) const
2018-09-28 17:54:21 +02:00
{
const LibertyLibrary *library = cell->libertyLibrary();
2018-11-26 18:15:52 +01:00
float delay = findValue(library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap);
float sigma_early = 0.0;
float sigma_late = 0.0;
2019-01-27 08:03:01 +01:00
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
2018-11-26 18:15:52 +01:00
sigma_early = findValue(library, cell, pvt,
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
2018-11-26 18:15:52 +01:00
sigma_late = findValue(library, cell, pvt,
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
gate_delay = makeDelay(delay, sigma_early, sigma_late);
float slew = findValue(library, cell, pvt, slew_model_, in_slew,
2018-09-28 17:54:21 +02:00
load_cap, related_out_cap);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
2018-11-26 18:15:52 +01:00
sigma_early = findValue(library, cell, pvt,
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
2018-11-26 18:15:52 +01:00
sigma_late = findValue(library, cell, pvt,
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
2018-09-28 17:54:21 +02:00
// Clip negative slews to zero.
2018-11-26 18:15:52 +01:00
if (slew < 0.0)
slew = 0.0;
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
2018-09-28 17:54:21 +02:00
}
void
GateTableModel::reportGateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
2019-01-27 08:03:01 +01:00
bool pocv_enabled,
2018-09-28 17:54:21 +02:00
int digits,
string *result) const
{
const LibertyLibrary *library = cell->libertyLibrary();
2018-12-05 23:18:41 +01:00
reportPvt(library, pvt, digits, result);
2018-09-28 17:54:21 +02:00
reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap, digits, result);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
2018-11-26 18:15:52 +01:00
reportTableLookup("Delay sigma(early)", library, cell, pvt,
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits, result);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
2018-11-26 18:15:52 +01:00
reportTableLookup("Delay sigma(late)", library, cell, pvt,
delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits, result);
2018-09-28 17:54:21 +02:00
*result += '\n';
reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew,
load_cap, related_out_cap, digits, result);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
2018-11-26 18:15:52 +01:00
reportTableLookup("Slew sigma(early)", library, cell, pvt,
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits, result);
2019-01-27 08:03:01 +01:00
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
2018-11-26 18:15:52 +01:00
reportTableLookup("Slew sigma(late)", library, cell, pvt,
slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits, result);
2018-09-28 17:54:21 +02:00
float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew,
load_cap, related_out_cap);
if (drvr_slew < 0.0)
*result += "Negative slew clipped to 0.0\n";
}
void
GateTableModel::reportTableLookup(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float in_slew,
float load_cap,
float related_out_cap,
int digits,
string *result) const
{
if (model) {
float axis_value1, axis_value2, axis_value3;
findAxisValues(model, in_slew, load_cap, related_out_cap,
axis_value1, axis_value2, axis_value3);
model->reportValue(result_name, library, cell, pvt,
axis_value1, NULL, axis_value2, axis_value3,
digits, result);
}
}
float
GateTableModel::findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float in_slew,
float load_cap,
float related_out_cap) const
{
if (model) {
float axis_value1, axis_value2, axis_value3;
findAxisValues(model, in_slew, load_cap, related_out_cap,
axis_value1, axis_value2, axis_value3);
return model->findValue(library, cell, pvt,
axis_value1, axis_value2, axis_value3);
}
else
return 0.0;
}
void
GateTableModel::findAxisValues(const TableModel *model,
float in_slew,
float load_cap,
float related_out_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,
related_out_cap);
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 2:
axis_value1 = axisValue(model->axis1(), in_slew, load_cap,
related_out_cap);
axis_value2 = axisValue(model->axis2(), in_slew, load_cap,
related_out_cap);
axis_value3 = 0.0;
break;
case 3:
axis_value1 = axisValue(model->axis1(), in_slew, load_cap,
related_out_cap);
axis_value2 = axisValue(model->axis2(), in_slew, load_cap,
related_out_cap);
axis_value3 = axisValue(model->axis3(), in_slew, load_cap,
related_out_cap);
break;
default:
internalError("unsupported table order");
}
}
// Use slew/Cload for the highest Cload, which approximates output
// admittance as the "drive".
float
GateTableModel::driveResistance(const LibertyCell *cell,
const Pvt *pvt) const
{
float slew, cap;
maxCapSlew(cell, 0.0, pvt, slew, cap);
return slew / cap;
}
void
GateTableModel::maxCapSlew(const LibertyCell *cell,
float in_slew,
const Pvt *pvt,
float &slew,
float &cap) const
{
const LibertyLibrary *library = cell->libertyLibrary();
TableAxis *axis1 = slew_model_->axis1();
TableAxis *axis2 = slew_model_->axis2();
TableAxis *axis3 = slew_model_->axis3();
if (axis1
&& axis1->variable() == table_axis_total_output_net_capacitance) {
cap = axis1->axisValue(axis1->size() - 1);
slew = findValue(library, cell, pvt, slew_model_,
in_slew, cap, 0.0);
}
else if (axis2
&& axis2->variable()==table_axis_total_output_net_capacitance) {
cap = axis2->axisValue(axis2->size() - 1);
slew = findValue(library, cell, pvt, slew_model_,
in_slew, cap, 0.0);
}
else if (axis3
&& axis3->variable()==table_axis_total_output_net_capacitance) {
cap = axis3->axisValue(axis3->size() - 1);
slew = findValue(library, cell, pvt, slew_model_,
in_slew, cap, 0.0);
}
else {
// Table not dependent on capacitance.
cap = 0.0;
slew = 1.0;
}
// Clip negative slews to zero.
if (slew < 0.0)
slew = 0.0;
}
float
GateTableModel::axisValue(TableAxis *axis,
float in_slew,
float load_cap,
float related_out_cap) const
{
TableAxisVariable var = axis->variable();
if (var == table_axis_input_transition_time
|| var == table_axis_input_net_transition)
return in_slew;
else if (var == table_axis_total_output_net_capacitance)
return load_cap;
else if (var == table_axis_related_out_total_output_net_capacitance)
return related_out_cap;
else {
internalError("unsupported table axes");
return 0.0;
}
}
bool
GateTableModel::checkAxes(const Table *table)
{
TableAxis *axis1 = table->axis1();
TableAxis *axis2 = table->axis2();
TableAxis *axis3 = table->axis3();
bool axis_ok = true;
if (axis1)
axis_ok &= checkAxis(table->axis1());
if (axis2)
axis_ok &= checkAxis(table->axis2());
if (axis3)
axis_ok &= checkAxis(table->axis3());
return axis_ok;
}
bool
GateTableModel::checkAxis(TableAxis *axis)
{
TableAxisVariable var = axis->variable();
return var == table_axis_total_output_net_capacitance
|| var == table_axis_input_transition_time
|| var == table_axis_input_net_transition
|| var == table_axis_related_out_total_output_net_capacitance;
}
////////////////////////////////////////////////////////////////
CheckTableModel::CheckTableModel(TableModel *model) :
model_(model)
{
}
CheckTableModel::~CheckTableModel()
{
delete model_;
}
void
CheckTableModel::setIsScaled(bool is_scaled)
{
model_->setIsScaled(is_scaled);
}
2018-11-26 18:15:52 +01:00
void
2018-09-28 17:54:21 +02:00
CheckTableModel::checkDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
float to_slew,
2018-11-26 18:15:52 +01:00
float related_out_cap,
2019-01-27 08:03:01 +01:00
bool pocv_enabled,
2018-11-26 18:15:52 +01:00
// Return values.
ArcDelay &margin) const
2018-09-28 17:54:21 +02:00
{
if (model_) {
2019-01-27 08:03:01 +01:00
const LibertyLibrary *library = cell->libertyLibrary();
float mean = findValue(library, cell, pvt, model_,
from_slew, to_slew, related_out_cap);
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(library, cell, pvt,
sigma_models_[EarlyLate::earlyIndex()],
from_slew, to_slew, related_out_cap);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(library, cell, pvt,
sigma_models_[EarlyLate::earlyIndex()],
from_slew, to_slew, related_out_cap);
margin = makeDelay(mean, sigma_early, sigma_late);
}
else
margin = 0.0;
}
float
CheckTableModel::findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float from_slew,
float to_slew,
float related_out_cap) const
{
if (model) {
2018-09-28 17:54:21 +02:00
float axis_value1, axis_value2, axis_value3;
findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3);
2019-01-27 08:03:01 +01:00
return model->findValue(library, cell, pvt,
axis_value1, axis_value2, axis_value3);
2018-09-28 17:54:21 +02:00
}
else
2019-01-27 08:03:01 +01:00
return 0.0;
2018-09-28 17:54:21 +02:00
}
void
CheckTableModel::reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
2019-01-27 08:03:01 +01:00
bool pocv_enabled,
2018-09-28 17:54:21 +02:00
int digits,
string *result) const
{
2019-01-27 08:03:01 +01:00
const LibertyLibrary *library = cell->libertyLibrary();
reportTableDelay("Check", library, cell, pvt, model_,
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits, result);
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
reportTableDelay("Check sigma early", library, cell, pvt,
sigma_models_[EarlyLate::earlyIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits, result);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
reportTableDelay("Check sigma late", library, cell, pvt,
sigma_models_[EarlyLate::lateIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits, result);
}
void
CheckTableModel::reportTableDelay(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
int digits,
string *result) const
{
if (model) {
2018-09-28 17:54:21 +02:00
float axis_value1, axis_value2, axis_value3;
findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3);
2018-12-05 23:18:41 +01:00
reportPvt(library, pvt, digits, result);
2019-01-27 08:03:01 +01:00
model_->reportValue(result_name, library, cell, pvt,
2018-09-28 17:54:21 +02:00
axis_value1, from_slew_annotation, axis_value2,
axis_value3, digits, result);
}
}
void
CheckTableModel::findAxisValues(float from_slew,
float to_slew,
float related_out_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(), from_slew, to_slew,
related_out_cap);
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 2:
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
related_out_cap);
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
related_out_cap);
axis_value3 = 0.0;
break;
case 3:
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
related_out_cap);
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
related_out_cap);
axis_value3 = axisValue(model_->axis3(), from_slew, to_slew,
related_out_cap);
break;
default:
internalError("unsupported table order");
}
}
float
CheckTableModel::axisValue(TableAxis *axis,
float from_slew,
float to_slew,
float related_out_cap) const
{
TableAxisVariable var = axis->variable();
if (var == table_axis_related_pin_transition)
return from_slew;
else if (var == table_axis_constrained_pin_transition)
return to_slew;
else if (var == table_axis_related_out_total_output_net_capacitance)
return related_out_cap;
else {
internalError("unsupported table axes");
return 0.0;
}
}
bool
CheckTableModel::checkAxes(const Table *table)
{
TableAxis *axis1 = table->axis1();
TableAxis *axis2 = table->axis2();
TableAxis *axis3 = table->axis3();
bool axis_ok = true;
if (axis1)
axis_ok &= checkAxis(table->axis1());
if (axis2)
axis_ok &= checkAxis(table->axis2());
if (axis3)
axis_ok &= checkAxis(table->axis3());
return axis_ok;
}
bool
CheckTableModel::checkAxis(TableAxis *axis)
{
TableAxisVariable var = axis->variable();
return var == table_axis_constrained_pin_transition
|| var == table_axis_related_pin_transition
|| var == table_axis_related_out_total_output_net_capacitance;
}
////////////////////////////////////////////////////////////////
TableModel::TableModel(Table *table,
ScaleFactorType scale_factor_type,
TransRiseFall *tr) :
table_(table),
scale_factor_type_(scale_factor_type),
tr_index_(tr->index()),
is_scaled_(false)
{
}
TableModel::~TableModel()
{
delete table_;
}
int
TableModel::order() const
{
return table_->order();
}
void
TableModel::setScaleFactorType(ScaleFactorType type)
{
scale_factor_type_ = type;
}
void
TableModel::setIsScaled(bool is_scaled)
{
is_scaled_ = is_scaled;
}
TableAxis *
TableModel::axis1() const
{
return table_->axis1();
}
TableAxis *
TableModel::axis2() const
{
return table_->axis2();
}
TableAxis *
TableModel::axis3() const
{
return table_->axis3();
}
float
TableModel::findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
float value2,
float value3) const
{
return table_->findValue(value1, value2, value3)
* scaleFactor(library, cell, pvt);
}
float
TableModel::scaleFactor(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt) const
{
if (is_scaled_)
// Scaled tables are not derated because scale factors are wrt
// nominal pvt.
return 1.0F;
else {
ScaleFactorType type = static_cast<ScaleFactorType>(scale_factor_type_);
return library->scaleFactor(type, tr_index_, cell, pvt);
}
}
void
TableModel::reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const
{
table_->reportValue("Table value", library, cell, pvt, value1,
comment1, value2, value3, digits, result);
reportPvtScaleFactor(library, cell, pvt, digits, result);
const Units *units = library->units();
const Unit *table_unit = units->timeUnit();
*result += result_name;
*result += " = ";
*result += table_unit->asString(findValue(library, cell, pvt,
value1, value2, value3), digits);
*result += '\n';
}
2018-11-26 18:15:52 +01:00
static void
reportPvt(const LibertyLibrary *library,
const Pvt *pvt,
int digits,
string *result)
2018-09-28 17:54:21 +02:00
{
if (pvt == NULL)
pvt = library->defaultOperatingConditions();
if (pvt) {
2019-01-17 00:37:31 +01:00
string pvt_str;
stringPrint(pvt_str, "P = %.*f V = %.*f T = %.*f\n",
digits, pvt->process(),
digits, pvt->voltage(),
digits, pvt->temperature());
2018-09-28 17:54:21 +02:00
*result += pvt_str;
}
2018-11-26 18:15:52 +01:00
}
void
TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
int digits,
string *result) const
{
if (pvt == NULL)
pvt = library->defaultOperatingConditions();
if (pvt) {
2019-01-17 00:37:31 +01:00
string scale_str;
stringPrint(scale_str, "PVT scale factor = %.*f\n",
digits,
scaleFactor(library, cell, pvt));
2018-11-26 18:15:52 +01:00
*result += scale_str;
}
2018-09-28 17:54:21 +02:00
}
////////////////////////////////////////////////////////////////
Table0::Table0(float value) :
Table(),
value_(value)
{
}
float
Table0::findValue(float,
float,
float) const
{
return value_;
}
void
Table0::reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *,
const Pvt *,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const
{
const Units *units = library->units();
const Unit *table_unit = units->timeUnit();
*result += result_name;
*result += " constant = ";
*result += table_unit->asString(findValue(value1, value2, value3), digits);
if (comment1)
*result += comment1;
*result += '\n';
}
void
Table0::report(const Units *units,
Report *report) const
{
int digits = 4;
const Unit *table_unit = units->timeUnit();
report->print("%s\n", table_unit->asString(value_, digits));
}
////////////////////////////////////////////////////////////////
Table1::Table1(FloatSeq *values,
TableAxis *axis1,
bool own_axis1) :
Table(),
values_(values),
axis1_(axis1),
own_axis1_(own_axis1)
{
}
Table1::~Table1()
{
delete values_;
if (own_axis1_)
delete axis1_;
}
float
Table1::tableValue(size_t index1) const
{
return (*values_)[index1];
}
float
Table1::findValue(float value1,
float,
float) const
{
if (axis1_->size() == 1)
return tableValue(value1);
else {
size_t index1 = axis1_->findAxisIndex(value1);
float x1 = value1;
float x1l = axis1_->axisValue(index1);
float x1u = axis1_->axisValue(index1 + 1);
float y1 = tableValue(index1);
float y2 = tableValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
return (1 - dx1) * y1 + dx1 * y2;
}
}
void
Table1::reportValue(const char *result_name, const
LibertyLibrary *library,
const LibertyCell *,
const Pvt *,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const
{
TableAxisVariable var1 = axis1_->variable();
const Units *units = library->units();
const Unit *table_unit = units->timeUnit();
const Unit *unit1 = tableVariableUnit(var1, units);
*result += "Table is indexed by\n";
*result += " ";
*result += tableVariableString(var1);
*result += " = ";
*result += unit1->asString(value1, digits);
if (comment1)
*result += comment1;
*result += '\n';
if (axis1_->size() != 1) {
size_t index1 = axis1_->findAxisIndex(value1);
*result += " ";
*result += unit1->asString(axis1_->axisValue(index1), digits);
*result += " ";
*result += unit1->asString(axis1_->axisValue(index1 + 1), digits);
*result += '\n';
*result += " --------------------\n";
*result += "| ";
*result += table_unit->asString(tableValue(index1), digits);
*result += " ";
*result += table_unit->asString(tableValue(index1 + 1),
digits);
*result += '\n';
}
*result += result_name;
*result += " = ";
*result += table_unit->asString(findValue(value1, value2, value3), digits);
*result += '\n';
}
void
Table1::report(const Units *units,
Report *report) const
{
int digits = 4;
const Unit *unit1 = tableVariableUnit(axis1_->variable(), units);
const Unit *table_unit = units->timeUnit();
report->print("%s\n", tableVariableString(axis1_->variable()));
report->print("------------------------------\n");
for (size_t index1 = 0; index1 < axis1_->size(); index1++)
report->print("%s ", unit1->asString(axis1_->axisValue(index1), digits));
report->print("\n");
for (size_t index1 = 0; index1 < axis1_->size(); index1++)
report->print("%s ", table_unit->asString(tableValue(index1),digits));
report->print("\n");
}
////////////////////////////////////////////////////////////////
Table2::Table2(FloatTable *values,
TableAxis *axis1,
bool own_axis1,
TableAxis *axis2,
bool own_axis2) :
Table(),
values_(values),
axis1_(axis1),
own_axis1_(own_axis1),
axis2_(axis2),
own_axis2_(own_axis2)
{
}
Table2::~Table2()
{
values_->deleteContents();
delete values_;
if (own_axis1_)
delete axis1_;
if (own_axis2_)
delete axis2_;
}
float
Table2::tableValue(size_t index1,
size_t index2) const
{
FloatSeq *row = (*values_)[index1];
return (*row)[index2];
}
// Bilinear Interpolation.
float
Table2::findValue(float value1,
float value2,
float) const
{
size_t size1 = axis1_->size();
size_t size2 = axis2_->size();
if (size1 == 1) {
if (size2 == 1)
return tableValue(0, 0);
else {
size_t index2 = axis2_->findAxisIndex(value2);
float x2 = value2;
float y00 = tableValue(0, index2);
float x2l = axis2_->axisValue(index2);
float x2u = axis2_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
float y01 = tableValue(0, index2 + 1);
float tbl_value
= (1 - dx2) * y00
+ dx2 * y01;
return tbl_value;
}
}
else if (size2 == 1) {
size_t index1 = axis1_->findAxisIndex(value1);
float x1 = value1;
float y00 = tableValue(index1, 0);
float x1l = axis1_->axisValue(index1);
float x1u = axis1_->axisValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
float y10 = tableValue(index1 + 1, 0);
float tbl_value
= (1 - dx1) * y00
+ dx1 * y10;
return tbl_value;
}
else {
size_t index1 = axis1_->findAxisIndex(value1);
size_t index2 = axis2_->findAxisIndex(value2);
float x1 = value1;
float x2 = value2;
float y00 = tableValue(index1, index2);
float x1l = axis1_->axisValue(index1);
float x1u = axis1_->axisValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
float y10 = tableValue(index1 + 1, index2);
float y11 = tableValue(index1 + 1, index2 + 1);
float x2l = axis2_->axisValue(index2);
float x2u = axis2_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
float y01 = tableValue(index1, index2 + 1);
float tbl_value
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
return tbl_value;
}
}
void
Table2::reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *,
const Pvt *,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const
{
TableAxisVariable var1 = axis1_->variable();
TableAxisVariable var2 = axis2_->variable();
const Units *units = library->units();
const Unit *table_unit = units->timeUnit();
const Unit *unit1 = tableVariableUnit(var1, units);
const Unit *unit2 = tableVariableUnit(var2, units);
*result += "------- ";
*result += tableVariableString(var1),
*result += " = ";
*result += unit1->asString(value1, digits);
if (comment1)
*result += comment1;
*result += '\n';
*result += "| ";
*result += tableVariableString(var2);
*result += " = ";
*result += unit2->asString(value2, digits);
*result += '\n';
size_t index1 = axis1_->findAxisIndex(value1);
size_t index2 = axis2_->findAxisIndex(value2);
*result += "| ";
*result += unit2->asString(axis2_->axisValue(index2), digits);
if (axis2_->size() != 1) {
*result += " ";
*result += unit2->asString(axis2_->axisValue(index2 + 1), digits);
}
*result += '\n';
*result += "v --------------------\n";
*result += unit1->asString(axis1_->axisValue(index1), digits);
*result += " | ";
*result += table_unit->asString(tableValue(index1, index2), digits);
if (axis2_->size() != 1) {
*result += " ";
*result += table_unit->asString(tableValue(index1, index2 + 1), digits);
}
*result += '\n';
if (axis1_->size() != 1) {
*result += unit1->asString(axis1_->axisValue(index1 + 1), digits);
*result += " | ";
*result += table_unit->asString(tableValue(index1 + 1, index2), digits);
if (axis2_->size() != 1) {
*result += " ";
*result +=table_unit->asString(tableValue(index1 + 1, index2 + 1),digits);
}
}
*result += '\n';
*result += result_name;
*result += " = ";
*result += table_unit->asString(findValue(value1, value2, value3), digits);
*result += '\n';
}
void
Table2::report(const Units *units,
Report *report) const
{
int digits = 4;
const Unit *table_unit = units->timeUnit();
const Unit *unit1 = tableVariableUnit(axis1_->variable(), units);
const Unit *unit2 = tableVariableUnit(axis2_->variable(), units);
report->print("%s\n", tableVariableString(axis2_->variable()));
report->print(" ------------------------------\n");
report->print(" ");
for (size_t index2 = 0; index2 < axis2_->size(); index2++)
report->print("%s ", unit2->asString(axis2_->axisValue(index2), digits));
report->print("\n");
for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
report->print("%s |", unit1->asString(axis1_->axisValue(index1), digits));
for (size_t index2 = 0; index2 < axis2_->size(); index2++)
report->print("%s ", table_unit->asString(tableValue(index1, index2),
digits));
report->print("\n");
}
}
////////////////////////////////////////////////////////////////
Table3::Table3(FloatTable *values,
TableAxis *axis1,
bool own_axis1,
TableAxis *axis2,
bool own_axis2,
TableAxis *axis3,
bool own_axis3) :
Table2(values, axis1, own_axis1, axis2, own_axis2),
axis3_(axis3),
own_axis3_(own_axis3)
{
}
Table3::~Table3()
{
if (own_axis3_)
delete axis3_;
}
float
Table3::tableValue(size_t index1,
size_t index2,
size_t index3) const
{
size_t row = index1 * axis2_->size() + index2;
return values_->operator[](row)->operator[](index3);
}
// Bilinear Interpolation.
float
Table3::findValue(float value1,
float value2,
float value3) const
{
size_t index1 = axis1_->findAxisIndex(value1);
size_t index2 = axis2_->findAxisIndex(value2);
size_t index3 = axis3_->findAxisIndex(value3);
float x1 = value1;
float x2 = value2;
float x3 = value3;
float dx1 = 0.0;
float dx2 = 0.0;
float dx3 = 0.0;
float y000 = tableValue(index1, index2, index3);
float y001 = 0.0;
float y010 = 0.0;
float y011 = 0.0;
float y100 = 0.0;
float y101 = 0.0;
float y110 = 0.0;
float y111 = 0.0;
if (axis1_->size() != 1) {
float x1l = axis1_->axisValue(index1);
float x1u = axis1_->axisValue(index1 + 1);
dx1 = (x1 - x1l) / (x1u - x1l);
y100 = tableValue(index1 + 1, index2, index3);
if (axis3_->size() != 1)
y101 = tableValue(index1 + 1, index2, index3 + 1);
if (axis2_->size() != 1) {
y110 = tableValue(index1 + 1, index2 + 1, index3);
if (axis3_->size() != 1)
y111 = tableValue(index1 + 1, index2 + 1, index3 + 1);
}
}
if (axis2_->size() != 1) {
float x2l = axis2_->axisValue(index2);
float x2u = axis2_->axisValue(index2 + 1);
dx2 = (x2 - x2l) / (x2u - x2l);
y010 = tableValue(index1, index2 + 1, index3);
if (axis3_->size() != 1)
y011 = tableValue(index1, index2 + 1, index3 + 1);
}
if (axis3_->size() != 1) {
float x3l = axis3_->axisValue(index3);
float x3u = axis3_->axisValue(index3 + 1);
dx3 = (x3 - x3l) / (x3u - x3l);
y001 = tableValue(index1, index2, index3 + 1);
}
float tbl_value
= (1 - dx1) * (1 - dx2) * (1 - dx3) * y000
+ (1 - dx1) * (1 - dx2) * dx3 * y001
+ (1 - dx1) * dx2 * (1 - dx3) * y010
+ (1 - dx1) * dx2 * dx3 * y011
+ dx1 * (1 - dx2) * (1 - dx3) * y100
+ dx1 * (1 - dx2) * dx3 * y101
+ dx1 * dx2 * (1 - dx3) * y110
+ dx1 * dx2 * dx3 * y111;
return tbl_value;
}
// Sample output.
//
// --------- input_net_transition = 0.00
// | ---- total_output_net_capacitance = 0.20
// | | related_out_total_output_net_capacitance = 0.10
// | | 0.00 0.30
// v | --------------------
// 0.01 v / 0.23 0.25
// 0.00 0.20 | 0.10 0.20
// |/ 0.30 0.32
// 0.40 | 0.20 0.30
void
Table3::reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *,
const Pvt *,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const
{
TableAxisVariable var1 = axis1_->variable();
TableAxisVariable var2 = axis2_->variable();
TableAxisVariable var3 = axis3_->variable();
const Units *units = library->units();
const Unit *table_unit = units->timeUnit();
const Unit *unit1 = tableVariableUnit(var1, units);
const Unit *unit2 = tableVariableUnit(var2, units);
const Unit *unit3 = tableVariableUnit(var3, units);
*result += " --------- ";
*result += tableVariableString(var1),
*result += " = ";
*result += unit1->asString(value1, digits);
if (comment1)
*result += comment1;
*result += '\n';
*result += " | ---- ";
*result += tableVariableString(var2),
*result += " = ";
*result += unit2->asString(value2, digits);
*result += '\n';
*result += " | | ";
*result += tableVariableString(var3);
*result += " = ";
*result += unit3->asString(value3, digits);
*result += '\n';
size_t index1 = axis1_->findAxisIndex(value1);
size_t index2 = axis2_->findAxisIndex(value2);
size_t index3 = axis3_->findAxisIndex(value3);
*result += " | | ";
*result += unit3->asString(axis3_->axisValue(index3), digits);
if (axis3_->size() != 1) {
*result += " ";
*result += unit3->asString(axis3_->axisValue(index3 + 1), digits);
}
*result += '\n';
*result += " v | --------------------\n";
if (axis1_->size() != 1) {
*result += " ";
*result += unit1->asString(axis1_->axisValue(index1+1), digits);
*result += " v / ";
*result += table_unit->asString(tableValue(index1+1,index2,index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
*result += table_unit->asString(tableValue(index1+1,index2,index3+1),
digits);
}
}
else {
appendSpaces(result, digits+3);
*result += " v / ";
}
*result += '\n';
*result += unit1->asString(axis1_->axisValue(index1), digits);
*result += " ";
*result += unit2->asString(axis2_->axisValue(index2), digits);
*result += " | ";
*result += table_unit->asString(tableValue(index1, index2, index3), digits);
if (axis3_->size() != 1) {
*result += " ";
*result += table_unit->asString(tableValue(index1, index2, index3+1),
digits);
}
*result += '\n';
*result += " |/ ";
if (axis1_->size() != 1
&& axis2_->size() != 1) {
*result += table_unit->asString(tableValue(index1+1,index2+1,index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
*result +=table_unit->asString(tableValue(index1+1,index2+1,index3+1),
digits);
}
}
*result += '\n';
*result += " ";
*result += unit2->asString(axis2_->axisValue(index2 + 1), digits);
*result += " | ";
if (axis2_->size() != 1) {
*result += table_unit->asString(tableValue(index1, index2+1, index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
*result +=table_unit->asString(tableValue(index1, index2+1,index3+1),
digits);
}
}
*result += '\n';
*result += result_name;
*result += " = ";
*result += table_unit->asString(findValue(value1, value2, value3), digits);
*result += '\n';
}
static void
appendSpaces(string *result,
int count)
{
while (count--)
*result += ' ';
}
void
Table3::report(const Units *units,
Report *report) const
{
int digits = 4;
const Unit *table_unit = units->timeUnit();
const Unit *unit1 = tableVariableUnit(axis1_->variable(), units);
const Unit *unit2 = tableVariableUnit(axis2_->variable(), units);
const Unit *unit3 = tableVariableUnit(axis3_->variable(), units);
for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
report->print("%s %s\n", tableVariableString(axis1_->variable()),
unit1->asString(axis1_->axisValue(index1), digits));
report->print("%s\n", tableVariableString(axis3_->variable()));
report->print(" ------------------------------\n");
report->print(" ");
for (size_t index3 = 0; index3 < axis3_->size(); index3++)
report->print("%s ", unit3->asString(axis3_->axisValue(index3), digits));
report->print("\n");
for (size_t index2 = 0; index2 < axis2_->size(); index2++) {
report->print("%s |", unit2->asString(axis2_->axisValue(index2),digits));
for (size_t index3 = 0; index3 < axis3_->size(); index3++)
report->print("%s ", table_unit->asString(tableValue(index1, index2,
index3),
digits));
report->print("\n");
}
}
}
////////////////////////////////////////////////////////////////
TableAxis::TableAxis(TableAxisVariable variable,
FloatSeq *values) :
variable_(variable),
values_(values)
{
}
TableAxis::~TableAxis()
{
delete values_;
}
// Bisection search.
size_t
TableAxis::findAxisIndex(float value) const
{
int max = static_cast<int>(values_->size()) - 1;
if (value <= (*values_)[0] || max == 0)
return 0;
else if (value >= (*values_)[max])
// Return max-1 for value too large so interpolation pts are index,index+1.
return max - 1;
else {
int lower = -1;
int upper = max + 1;
bool ascend = ((*values_)[max] >= (*values_)[0]);
while (upper - lower > 1) {
int mid = (upper + lower) >> 1;
if ((value >= (*values_)[mid]) == ascend)
lower = mid;
else
upper = mid;
}
return lower;
}
}
////////////////////////////////////////////////////////////////
TableAxisVariable
stringTableAxisVariable(const char *variable)
{
if (stringEq(variable, "total_output_net_capacitance"))
return table_axis_total_output_net_capacitance;
if (stringEq(variable, "equal_or_opposite_output_net_capacitance"))
return table_axis_equal_or_opposite_output_net_capacitance;
else if (stringEq(variable, "input_net_transition"))
return table_axis_input_net_transition;
else if (stringEq(variable, "input_transition_time"))
return table_axis_input_transition_time;
else if (stringEq(variable, "related_pin_transition"))
return table_axis_related_pin_transition;
else if (stringEq(variable, "constrained_pin_transition"))
return table_axis_constrained_pin_transition;
else if (stringEq(variable, "output_pin_transition"))
return table_axis_output_pin_transition;
else if (stringEq(variable, "connect_delay"))
return table_axis_connect_delay;
else if (stringEq(variable,"related_out_total_output_net_capacitance"))
return table_axis_related_out_total_output_net_capacitance;
else if (stringEq(variable, "time"))
return table_axis_time;
else if (stringEq(variable, "iv_output_voltage"))
return table_axis_iv_output_voltage;
else if (stringEq(variable, "input_noise_width"))
return table_axis_input_noise_width;
else if (stringEq(variable, "input_noise_height"))
return table_axis_input_noise_height;
else if (stringEq(variable, "input_voltage"))
return table_axis_input_voltage;
else if (stringEq(variable, "output_voltage"))
return table_axis_output_voltage;
else if (stringEq(variable, "path_depth"))
return table_axis_path_depth;
else if (stringEq(variable, "path_distance"))
return table_axis_path_distance;
2018-12-26 20:03:31 +01:00
else if (stringEq(variable, "normalzied_voltage"))
return table_axis_normalized_voltage;
2018-09-28 17:54:21 +02:00
else
return table_axis_unknown;
}
const char *
tableVariableString(TableAxisVariable variable)
{
switch (variable) {
case table_axis_total_output_net_capacitance:
return "total_output_net_capacitance";
case table_axis_equal_or_opposite_output_net_capacitance:
return "equal_or_opposite_output_net_capacitance";
case table_axis_input_net_transition:
return "input_net_transition";
case table_axis_input_transition_time:
return "input_transition_time";
case table_axis_related_pin_transition:
return "related_pin_transition";
case table_axis_constrained_pin_transition:
return "constrained_pin_transition";
case table_axis_output_pin_transition:
return "output_pin_transition";
case table_axis_connect_delay:
return "connect_delay";
case table_axis_related_out_total_output_net_capacitance:
return "related_out_total_output_net_capacitance";
case table_axis_time:
return "time";
case table_axis_iv_output_voltage:
return "iv_output_voltage";
case table_axis_input_noise_width:
return "input_noise_width";
case table_axis_input_noise_height:
return "input_noise_height";
default:
return "unknown";
}
}
const Unit *
tableVariableUnit(TableAxisVariable variable,
const Units *units)
{
switch (variable) {
case table_axis_total_output_net_capacitance:
case table_axis_related_out_total_output_net_capacitance:
case table_axis_equal_or_opposite_output_net_capacitance:
return units->capacitanceUnit();
case table_axis_input_net_transition:
case table_axis_input_transition_time:
case table_axis_related_pin_transition:
case table_axis_constrained_pin_transition:
case table_axis_output_pin_transition:
case table_axis_connect_delay:
case table_axis_time:
case table_axis_input_noise_height:
return units->timeUnit();
case table_axis_input_voltage:
case table_axis_output_voltage:
case table_axis_iv_output_voltage:
case table_axis_input_noise_width:
return units->voltageUnit();
case table_axis_path_distance:
return units->distanceUnit();
case table_axis_path_depth:
2018-12-26 20:03:31 +01:00
case table_axis_normalized_voltage:
2018-09-28 17:54:21 +02:00
case table_axis_unknown:
return units->scalarUnit();
}
// Prevent warnings from lame compilers.
return NULL;
}
} // namespace