2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2022-01-04 18:17:08 +01:00
|
|
|
// Copyright (c) 2022, 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
|
2022-01-04 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "TableModel.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-12-28 18:04:57 +01:00
|
|
|
#include <string>
|
|
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Error.hh"
|
|
|
|
|
#include "EnumNameMap.hh"
|
|
|
|
|
#include "Units.hh"
|
|
|
|
|
#include "Liberty.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2020-12-28 18:04:57 +01:00
|
|
|
using std::string;
|
|
|
|
|
|
2019-06-04 17:12:22 +02:00
|
|
|
static void
|
|
|
|
|
deleteSigmaModels(TableModel *models[EarlyLate::index_count]);
|
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)
|
|
|
|
|
{
|
2019-07-18 15:19:00 +02:00
|
|
|
for (auto el_index : EarlyLate::rangeIndex()) {
|
2022-06-09 03:54:56 +02:00
|
|
|
slew_sigma_models_[el_index] = slew_sigma_models ? slew_sigma_models[el_index] : nullptr;
|
|
|
|
|
delay_sigma_models_[el_index] = delay_sigma_models ? delay_sigma_models[el_index] : nullptr;
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GateTableModel::~GateTableModel()
|
|
|
|
|
{
|
|
|
|
|
delete delay_model_;
|
|
|
|
|
delete slew_model_;
|
2019-03-27 00:07:32 +01:00
|
|
|
deleteSigmaModels(slew_sigma_models_);
|
|
|
|
|
deleteSigmaModels(delay_sigma_models_);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 17:12:22 +02:00
|
|
|
static void
|
|
|
|
|
deleteSigmaModels(TableModel *models[EarlyLate::index_count])
|
2019-03-27 00:07:32 +01:00
|
|
|
{
|
|
|
|
|
TableModel *early_model = models[EarlyLate::earlyIndex()];
|
|
|
|
|
TableModel *late_model = models[EarlyLate::lateIndex()];
|
|
|
|
|
if (early_model == late_model)
|
|
|
|
|
delete early_model;
|
|
|
|
|
else {
|
|
|
|
|
delete early_model;
|
|
|
|
|
delete late_model;
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
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,
|
2019-12-21 01:23:48 +01:00
|
|
|
delay_sigma_models_[EarlyLate::lateIndex()],
|
2018-11-26 18:15:52 +01:00
|
|
|
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,
|
2019-12-21 01:23:48 +01:00
|
|
|
slew_sigma_models_[EarlyLate::lateIndex()],
|
2018-11-26 18:15:52 +01:00
|
|
|
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,
|
2019-03-13 01:25:53 +01:00
|
|
|
axis_value1, nullptr, axis_value2, axis_value3,
|
2018-09-28 17:54:21 +02:00
|
|
|
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:
|
2021-02-06 23:59:57 +01:00
|
|
|
axis_value1 = 0.0;
|
|
|
|
|
axis_value2 = 0.0;
|
|
|
|
|
axis_value3 = 0.0;
|
2020-12-14 02:21:35 +01:00
|
|
|
criticalError(239, "unsupported table order");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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();
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1 = slew_model_->axis1();
|
|
|
|
|
TableAxisPtr axis2 = slew_model_->axis2();
|
|
|
|
|
TableAxisPtr axis3 = slew_model_->axis3();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis1
|
2019-03-13 01:25:53 +01:00
|
|
|
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
|
2018-09-28 17:54:21 +02:00
|
|
|
cap = axis1->axisValue(axis1->size() - 1);
|
|
|
|
|
slew = findValue(library, cell, pvt, slew_model_,
|
|
|
|
|
in_slew, cap, 0.0);
|
|
|
|
|
}
|
|
|
|
|
else if (axis2
|
2019-03-13 01:25:53 +01:00
|
|
|
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
|
2018-09-28 17:54:21 +02:00
|
|
|
cap = axis2->axisValue(axis2->size() - 1);
|
|
|
|
|
slew = findValue(library, cell, pvt, slew_model_,
|
|
|
|
|
in_slew, cap, 0.0);
|
|
|
|
|
}
|
|
|
|
|
else if (axis3
|
2019-03-13 01:25:53 +01:00
|
|
|
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
|
2018-09-28 17:54:21 +02:00
|
|
|
cap = axis3->axisValue(axis3->size() - 1);
|
|
|
|
|
slew = findValue(library, cell, pvt, slew_model_,
|
|
|
|
|
in_slew, cap, 0.0);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Table not dependent on capacitance.
|
2019-06-22 20:17:13 +02:00
|
|
|
cap = 1.0;
|
|
|
|
|
slew = 0.0;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
// Clip negative slews to zero.
|
|
|
|
|
if (slew < 0.0)
|
|
|
|
|
slew = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2022-06-26 01:31:18 +02:00
|
|
|
GateTableModel::axisValue(TableAxisPtr axis,
|
2018-09-28 17:54:21 +02:00
|
|
|
float in_slew,
|
|
|
|
|
float load_cap,
|
|
|
|
|
float related_out_cap) const
|
|
|
|
|
{
|
|
|
|
|
TableAxisVariable var = axis->variable();
|
2019-03-13 01:25:53 +01:00
|
|
|
if (var == TableAxisVariable::input_transition_time
|
|
|
|
|
|| var == TableAxisVariable::input_net_transition)
|
2018-09-28 17:54:21 +02:00
|
|
|
return in_slew;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (var == TableAxisVariable::total_output_net_capacitance)
|
2018-09-28 17:54:21 +02:00
|
|
|
return load_cap;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (var == TableAxisVariable::related_out_total_output_net_capacitance)
|
2018-09-28 17:54:21 +02:00
|
|
|
return related_out_cap;
|
|
|
|
|
else {
|
2020-12-14 02:21:35 +01:00
|
|
|
criticalError(240, "unsupported table axes");
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2023-01-18 18:23:03 +01:00
|
|
|
GateTableModel::checkAxes(const TablePtr table)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1 = table->axis1();
|
|
|
|
|
TableAxisPtr axis2 = table->axis2();
|
|
|
|
|
TableAxisPtr axis3 = table->axis3();
|
2018-09-28 17:54:21 +02:00
|
|
|
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
|
2022-06-26 01:31:18 +02:00
|
|
|
GateTableModel::checkAxis(TableAxisPtr axis)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
TableAxisVariable var = axis->variable();
|
2019-03-13 01:25:53 +01:00
|
|
|
return var == TableAxisVariable::total_output_net_capacitance
|
|
|
|
|
|| var == TableAxisVariable::input_transition_time
|
|
|
|
|
|| var == TableAxisVariable::input_net_transition
|
|
|
|
|
|| var == TableAxisVariable::related_out_total_output_net_capacitance;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-06-04 17:12:22 +02:00
|
|
|
CheckTableModel::CheckTableModel(TableModel *model,
|
|
|
|
|
TableModel *sigma_models[EarlyLate::index_count]) :
|
2018-09-28 17:54:21 +02:00
|
|
|
model_(model)
|
|
|
|
|
{
|
2019-07-18 15:19:00 +02:00
|
|
|
for (auto el_index : EarlyLate::rangeIndex())
|
2022-06-08 19:03:41 +02:00
|
|
|
sigma_models_[el_index] = sigma_models ? sigma_models[el_index] : nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CheckTableModel::~CheckTableModel()
|
|
|
|
|
{
|
|
|
|
|
delete model_;
|
2019-06-04 17:12:22 +02:00
|
|
|
deleteSigmaModels(sigma_models_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
2020-11-02 19:44:13 +01:00
|
|
|
sigma_models_[EarlyLate::lateIndex()],
|
2019-01-27 08:03:01 +01:00
|
|
|
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:
|
2020-12-14 02:21:35 +01:00
|
|
|
criticalError(241, "unsupported table order");
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2022-06-26 01:31:18 +02:00
|
|
|
CheckTableModel::axisValue(TableAxisPtr axis,
|
2018-09-28 17:54:21 +02:00
|
|
|
float from_slew,
|
|
|
|
|
float to_slew,
|
|
|
|
|
float related_out_cap) const
|
|
|
|
|
{
|
|
|
|
|
TableAxisVariable var = axis->variable();
|
2019-03-13 01:25:53 +01:00
|
|
|
if (var == TableAxisVariable::related_pin_transition)
|
2018-09-28 17:54:21 +02:00
|
|
|
return from_slew;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (var == TableAxisVariable::constrained_pin_transition)
|
2018-09-28 17:54:21 +02:00
|
|
|
return to_slew;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (var == TableAxisVariable::related_out_total_output_net_capacitance)
|
2018-09-28 17:54:21 +02:00
|
|
|
return related_out_cap;
|
|
|
|
|
else {
|
2020-12-14 02:21:35 +01:00
|
|
|
criticalError(242, "unsupported table axes");
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2023-01-18 18:23:03 +01:00
|
|
|
CheckTableModel::checkAxes(const TablePtr table)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1 = table->axis1();
|
|
|
|
|
TableAxisPtr axis2 = table->axis2();
|
|
|
|
|
TableAxisPtr axis3 = table->axis3();
|
2018-09-28 17:54:21 +02:00
|
|
|
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
|
2022-06-26 01:31:18 +02:00
|
|
|
CheckTableModel::checkAxis(TableAxisPtr axis)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
TableAxisVariable var = axis->variable();
|
2019-03-13 01:25:53 +01:00
|
|
|
return var == TableAxisVariable::constrained_pin_transition
|
|
|
|
|
|| var == TableAxisVariable::related_pin_transition
|
|
|
|
|
|| var == TableAxisVariable::related_out_total_output_net_capacitance;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-01-18 18:23:03 +01:00
|
|
|
TableModel::TableModel(TablePtr table,
|
2022-06-07 05:57:09 +02:00
|
|
|
TableTemplate *tbl_template,
|
2018-09-28 17:54:21 +02:00
|
|
|
ScaleFactorType scale_factor_type,
|
2019-11-11 23:30:19 +01:00
|
|
|
RiseFall *rf) :
|
2018-09-28 17:54:21 +02:00
|
|
|
table_(table),
|
2022-06-07 05:57:09 +02:00
|
|
|
tbl_template_(tbl_template),
|
2019-03-13 01:25:53 +01:00
|
|
|
scale_factor_type_(int(scale_factor_type)),
|
2019-11-11 23:30:19 +01:00
|
|
|
tr_index_(rf->index()),
|
2018-09-28 17:54:21 +02:00
|
|
|
is_scaled_(false)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
TableModel::order() const
|
|
|
|
|
{
|
|
|
|
|
return table_->order();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TableModel::setScaleFactorType(ScaleFactorType type)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
scale_factor_type_ = int(type);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TableModel::setIsScaled(bool is_scaled)
|
|
|
|
|
{
|
|
|
|
|
is_scaled_ = is_scaled;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr
|
2018-09-28 17:54:21 +02:00
|
|
|
TableModel::axis1() const
|
|
|
|
|
{
|
|
|
|
|
return table_->axis1();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr
|
2018-09-28 17:54:21 +02:00
|
|
|
TableModel::axis2() const
|
|
|
|
|
{
|
|
|
|
|
return table_->axis2();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr
|
2018-09-28 17:54:21 +02:00
|
|
|
TableModel::axis3() const
|
|
|
|
|
{
|
|
|
|
|
return table_->axis3();
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-07 05:57:09 +02:00
|
|
|
float
|
|
|
|
|
TableModel::value(size_t index1,
|
|
|
|
|
size_t index2,
|
|
|
|
|
size_t index3) const
|
|
|
|
|
{
|
|
|
|
|
return table_->value(index1, index2, index3);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
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;
|
2019-03-13 01:25:53 +01:00
|
|
|
else
|
|
|
|
|
return library->scaleFactor(static_cast<ScaleFactorType>(scale_factor_type_),
|
|
|
|
|
tr_index_, cell, pvt);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (pvt == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
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
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (pvt == nullptr)
|
2018-11-26 18:15:52 +01:00
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-07 05:57:09 +02:00
|
|
|
float
|
|
|
|
|
Table0::value(size_t,
|
|
|
|
|
size_t,
|
|
|
|
|
size_t) const
|
|
|
|
|
{
|
|
|
|
|
return value_;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
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();
|
2020-12-28 18:04:57 +01:00
|
|
|
report->reportLine("%s", table_unit->asString(value_, digits));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Table1::Table1(FloatSeq *values,
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1) :
|
2018-09-28 17:54:21 +02:00
|
|
|
Table(),
|
|
|
|
|
values_(values),
|
2022-06-26 01:31:18 +02:00
|
|
|
axis1_(axis1)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Table1::~Table1()
|
|
|
|
|
{
|
|
|
|
|
delete values_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2022-06-07 05:57:09 +02:00
|
|
|
Table1::value(size_t index1,
|
|
|
|
|
size_t,
|
|
|
|
|
size_t) const
|
|
|
|
|
{
|
|
|
|
|
return value(index1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
Table1::value(size_t index1) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return (*values_)[index1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
Table1::findValue(float value1,
|
|
|
|
|
float,
|
|
|
|
|
float) const
|
|
|
|
|
{
|
|
|
|
|
if (axis1_->size() == 1)
|
2022-06-07 05:57:09 +02:00
|
|
|
return value(value1);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
size_t index1 = axis1_->findAxisIndex(value1);
|
|
|
|
|
float x1 = value1;
|
|
|
|
|
float x1l = axis1_->axisValue(index1);
|
|
|
|
|
float x1u = axis1_->axisValue(index1 + 1);
|
2022-06-07 05:57:09 +02:00
|
|
|
float y1 = value(index1);
|
|
|
|
|
float y2 = value(index1 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
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 += "| ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1), digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1 + 1),
|
2018-09-28 17:54:21 +02:00
|
|
|
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();
|
2020-12-28 18:04:57 +01:00
|
|
|
report->reportLine("%s", tableVariableString(axis1_->variable()));
|
|
|
|
|
report->reportLine("------------------------------");
|
|
|
|
|
string line;
|
|
|
|
|
for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
|
|
|
|
|
line += unit1->asString(axis1_->axisValue(index1), digits);
|
|
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2020-12-28 18:04:57 +01:00
|
|
|
|
|
|
|
|
line.clear();
|
|
|
|
|
for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
|
2022-06-07 05:57:09 +02:00
|
|
|
line += table_unit->asString(value(index1), digits);
|
2020-12-28 18:04:57 +01:00
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Table2::Table2(FloatTable *values,
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1,
|
|
|
|
|
TableAxisPtr axis2) :
|
2018-09-28 17:54:21 +02:00
|
|
|
Table(),
|
|
|
|
|
values_(values),
|
|
|
|
|
axis1_(axis1),
|
2022-06-26 01:31:18 +02:00
|
|
|
axis2_(axis2)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Table2::~Table2()
|
|
|
|
|
{
|
|
|
|
|
values_->deleteContents();
|
|
|
|
|
delete values_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2022-06-07 05:57:09 +02:00
|
|
|
Table2::value(size_t index1,
|
|
|
|
|
size_t index2,
|
|
|
|
|
size_t) const
|
|
|
|
|
{
|
|
|
|
|
return value(index1, index2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
Table2::value(size_t index1,
|
|
|
|
|
size_t index2) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
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)
|
2022-06-07 05:57:09 +02:00
|
|
|
return value(0, 0);
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
size_t index2 = axis2_->findAxisIndex(value2);
|
|
|
|
|
float x2 = value2;
|
2022-06-07 05:57:09 +02:00
|
|
|
float y00 = value(0, index2);
|
2018-09-28 17:54:21 +02:00
|
|
|
float x2l = axis2_->axisValue(index2);
|
|
|
|
|
float x2u = axis2_->axisValue(index2 + 1);
|
|
|
|
|
float dx2 = (x2 - x2l) / (x2u - x2l);
|
2022-06-07 05:57:09 +02:00
|
|
|
float y01 = value(0, index2 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
float tbl_value
|
|
|
|
|
= (1 - dx2) * y00
|
|
|
|
|
+ dx2 * y01;
|
|
|
|
|
return tbl_value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (size2 == 1) {
|
|
|
|
|
size_t index1 = axis1_->findAxisIndex(value1);
|
|
|
|
|
float x1 = value1;
|
2022-06-07 05:57:09 +02:00
|
|
|
float y00 = value(index1, 0);
|
2018-09-28 17:54:21 +02:00
|
|
|
float x1l = axis1_->axisValue(index1);
|
|
|
|
|
float x1u = axis1_->axisValue(index1 + 1);
|
|
|
|
|
float dx1 = (x1 - x1l) / (x1u - x1l);
|
2022-06-07 05:57:09 +02:00
|
|
|
float y10 = value(index1 + 1, 0);
|
2018-09-28 17:54:21 +02:00
|
|
|
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;
|
2022-06-07 05:57:09 +02:00
|
|
|
float y00 = value(index1, index2);
|
2018-09-28 17:54:21 +02:00
|
|
|
float x1l = axis1_->axisValue(index1);
|
|
|
|
|
float x1u = axis1_->axisValue(index1 + 1);
|
|
|
|
|
float dx1 = (x1 - x1l) / (x1u - x1l);
|
2022-06-07 05:57:09 +02:00
|
|
|
float y10 = value(index1 + 1, index2);
|
|
|
|
|
float y11 = value(index1 + 1, index2 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
float x2l = axis2_->axisValue(index2);
|
|
|
|
|
float x2u = axis2_->axisValue(index2 + 1);
|
|
|
|
|
float dx2 = (x2 - x2l) / (x2u - x2l);
|
2022-06-07 05:57:09 +02:00
|
|
|
float y01 = value(index1, index2 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
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 += " | ";
|
|
|
|
|
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1, index2), digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis2_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1, index2 + 1), digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
*result += '\n';
|
|
|
|
|
|
|
|
|
|
if (axis1_->size() != 1) {
|
|
|
|
|
*result += unit1->asString(axis1_->axisValue(index1 + 1), digits);
|
|
|
|
|
*result += " | ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1 + 1, index2), digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis2_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result +=table_unit->asString(value(index1 + 1, index2 + 1),digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*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);
|
2020-12-28 18:04:57 +01:00
|
|
|
report->reportLine("%s", tableVariableString(axis2_->variable()));
|
|
|
|
|
report->reportLine(" ------------------------------");
|
|
|
|
|
string line = " ";
|
|
|
|
|
for (size_t index2 = 0; index2 < axis2_->size(); index2++) {
|
|
|
|
|
line += unit2->asString(axis2_->axisValue(index2), digits);
|
|
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
|
2020-12-28 18:04:57 +01:00
|
|
|
line = unit1->asString(axis1_->axisValue(index1), digits);
|
|
|
|
|
line += " |";
|
|
|
|
|
for (size_t index2 = 0; index2 < axis2_->size(); index2++) {
|
2022-06-07 05:57:09 +02:00
|
|
|
line += table_unit->asString(value(index1, index2), digits);
|
2020-12-28 18:04:57 +01:00
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Table3::Table3(FloatTable *values,
|
2022-06-26 01:31:18 +02:00
|
|
|
TableAxisPtr axis1,
|
|
|
|
|
TableAxisPtr axis2,
|
|
|
|
|
TableAxisPtr axis3) :
|
|
|
|
|
Table2(values, axis1, axis2),
|
|
|
|
|
axis3_(axis3)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2022-06-07 05:57:09 +02:00
|
|
|
Table3::value(size_t index1,
|
|
|
|
|
size_t index2,
|
|
|
|
|
size_t index3) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
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;
|
2022-06-07 05:57:09 +02:00
|
|
|
float y000 = value(index1, index2, index3);
|
2018-09-28 17:54:21 +02:00
|
|
|
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);
|
2022-06-07 05:57:09 +02:00
|
|
|
y100 = value(index1 + 1, index2, index3);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis3_->size() != 1)
|
2022-06-07 05:57:09 +02:00
|
|
|
y101 = value(index1 + 1, index2, index3 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis2_->size() != 1) {
|
2022-06-07 05:57:09 +02:00
|
|
|
y110 = value(index1 + 1, index2 + 1, index3);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis3_->size() != 1)
|
2022-06-07 05:57:09 +02:00
|
|
|
y111 = value(index1 + 1, index2 + 1, index3 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (axis2_->size() != 1) {
|
|
|
|
|
float x2l = axis2_->axisValue(index2);
|
|
|
|
|
float x2u = axis2_->axisValue(index2 + 1);
|
|
|
|
|
dx2 = (x2 - x2l) / (x2u - x2l);
|
2022-06-07 05:57:09 +02:00
|
|
|
y010 = value(index1, index2 + 1, index3);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis3_->size() != 1)
|
2022-06-07 05:57:09 +02:00
|
|
|
y011 = value(index1, index2 + 1, index3 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if (axis3_->size() != 1) {
|
|
|
|
|
float x3l = axis3_->axisValue(index3);
|
|
|
|
|
float x3u = axis3_->axisValue(index3 + 1);
|
|
|
|
|
dx3 = (x3 - x3l) / (x3u - x3l);
|
2022-06-07 05:57:09 +02:00
|
|
|
y001 = value(index1, index2, index3 + 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 / ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1+1,index2,index3),
|
2018-09-28 17:54:21 +02:00
|
|
|
digits);
|
|
|
|
|
if (axis3_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1+1,index2,index3+1),
|
2018-09-28 17:54:21 +02:00
|
|
|
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 += " | ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1, index2, index3), digits);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (axis3_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1, index2, index3+1),
|
2018-09-28 17:54:21 +02:00
|
|
|
digits);
|
|
|
|
|
}
|
|
|
|
|
*result += '\n';
|
|
|
|
|
|
|
|
|
|
*result += " |/ ";
|
|
|
|
|
if (axis1_->size() != 1
|
|
|
|
|
&& axis2_->size() != 1) {
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1+1,index2+1,index3),
|
2018-09-28 17:54:21 +02:00
|
|
|
digits);
|
|
|
|
|
if (axis3_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result +=table_unit->asString(value(index1+1,index2+1,index3+1),
|
2018-09-28 17:54:21 +02:00
|
|
|
digits);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*result += '\n';
|
|
|
|
|
|
|
|
|
|
*result += " ";
|
|
|
|
|
*result += unit2->asString(axis2_->axisValue(index2 + 1), digits);
|
|
|
|
|
*result += " | ";
|
|
|
|
|
if (axis2_->size() != 1) {
|
2022-06-07 05:57:09 +02:00
|
|
|
*result += table_unit->asString(value(index1, index2+1, index3),
|
2018-09-28 17:54:21 +02:00
|
|
|
digits);
|
|
|
|
|
if (axis3_->size() != 1) {
|
|
|
|
|
*result += " ";
|
2022-06-07 05:57:09 +02:00
|
|
|
*result +=table_unit->asString(value(index1, index2+1,index3+1),
|
2018-09-28 17:54:21 +02:00
|
|
|
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++) {
|
2020-12-28 18:04:57 +01:00
|
|
|
report->reportLine("%s %s", tableVariableString(axis1_->variable()),
|
|
|
|
|
unit1->asString(axis1_->axisValue(index1), digits));
|
|
|
|
|
|
|
|
|
|
report->reportLine("%s", tableVariableString(axis3_->variable()));
|
|
|
|
|
report->reportLine(" ------------------------------");
|
|
|
|
|
string line = " ";
|
|
|
|
|
for (size_t index3 = 0; index3 < axis3_->size(); index3++) {
|
|
|
|
|
line += unit3->asString(axis3_->axisValue(index3), digits);
|
|
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
for (size_t index2 = 0; index2 < axis2_->size(); index2++) {
|
2020-12-28 18:04:57 +01:00
|
|
|
line = unit2->asString(axis2_->axisValue(index2),digits);
|
|
|
|
|
line += " |";
|
|
|
|
|
for (size_t index3 = 0; index3 < axis3_->size(); index3++) {
|
2022-06-07 05:57:09 +02:00
|
|
|
line += table_unit->asString(value(index1, index2, index3), digits);
|
2020-12-28 18:04:57 +01:00
|
|
|
line += " ";
|
|
|
|
|
}
|
2021-01-05 03:14:04 +01:00
|
|
|
report->reportLineString(line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-03-29 22:18:08 +01:00
|
|
|
static EnumNameMap<TableAxisVariable> table_axis_variable_map =
|
|
|
|
|
{{TableAxisVariable::total_output_net_capacitance, "total_output_net_capacitance"},
|
|
|
|
|
{TableAxisVariable::equal_or_opposite_output_net_capacitance, "equal_or_opposite_output_net_capacitance"},
|
|
|
|
|
{TableAxisVariable::input_net_transition, "input_net_transition"},
|
|
|
|
|
{TableAxisVariable::input_transition_time, "input_transition_time"},
|
|
|
|
|
{TableAxisVariable::related_pin_transition, "related_pin_transition"},
|
|
|
|
|
{TableAxisVariable::constrained_pin_transition, "constrained_pin_transition"},
|
|
|
|
|
{TableAxisVariable::output_pin_transition, "output_pin_transition"},
|
|
|
|
|
{TableAxisVariable::connect_delay, "connect_delay"},
|
|
|
|
|
{TableAxisVariable::related_out_total_output_net_capacitance, "related_out_total_output_net_capacitance"},
|
|
|
|
|
{TableAxisVariable::time, "time"},
|
|
|
|
|
{TableAxisVariable::iv_output_voltage, "iv_output_voltage"},
|
|
|
|
|
{TableAxisVariable::input_noise_width, "input_noise_width"},
|
|
|
|
|
{TableAxisVariable::input_noise_height, "input_noise_height"},
|
|
|
|
|
{TableAxisVariable::input_voltage, "input_voltage"},
|
|
|
|
|
{TableAxisVariable::output_voltage, "output_voltage"},
|
|
|
|
|
{TableAxisVariable::path_depth, "path_depth"},
|
|
|
|
|
{TableAxisVariable::path_distance, "path_distance"},
|
|
|
|
|
{TableAxisVariable::normalized_voltage, "normalized_voltage"}
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
TableAxisVariable
|
|
|
|
|
stringTableAxisVariable(const char *variable)
|
|
|
|
|
{
|
2019-03-29 22:18:08 +01:00
|
|
|
return table_axis_variable_map.find(variable, TableAxisVariable::unknown);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
tableVariableString(TableAxisVariable variable)
|
|
|
|
|
{
|
2019-03-29 22:18:08 +01:00
|
|
|
return table_axis_variable_map.find(variable);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Unit *
|
|
|
|
|
tableVariableUnit(TableAxisVariable variable,
|
|
|
|
|
const Units *units)
|
|
|
|
|
{
|
|
|
|
|
switch (variable) {
|
2019-03-13 01:25:53 +01:00
|
|
|
case TableAxisVariable::total_output_net_capacitance:
|
|
|
|
|
case TableAxisVariable::related_out_total_output_net_capacitance:
|
|
|
|
|
case TableAxisVariable::equal_or_opposite_output_net_capacitance:
|
2018-09-28 17:54:21 +02:00
|
|
|
return units->capacitanceUnit();
|
2019-03-13 01:25:53 +01:00
|
|
|
case TableAxisVariable::input_net_transition:
|
|
|
|
|
case TableAxisVariable::input_transition_time:
|
|
|
|
|
case TableAxisVariable::related_pin_transition:
|
|
|
|
|
case TableAxisVariable::constrained_pin_transition:
|
|
|
|
|
case TableAxisVariable::output_pin_transition:
|
|
|
|
|
case TableAxisVariable::connect_delay:
|
|
|
|
|
case TableAxisVariable::time:
|
|
|
|
|
case TableAxisVariable::input_noise_height:
|
2018-09-28 17:54:21 +02:00
|
|
|
return units->timeUnit();
|
2019-03-13 01:25:53 +01:00
|
|
|
case TableAxisVariable::input_voltage:
|
|
|
|
|
case TableAxisVariable::output_voltage:
|
|
|
|
|
case TableAxisVariable::iv_output_voltage:
|
|
|
|
|
case TableAxisVariable::input_noise_width:
|
2018-09-28 17:54:21 +02:00
|
|
|
return units->voltageUnit();
|
2019-03-13 01:25:53 +01:00
|
|
|
case TableAxisVariable::path_distance:
|
2018-09-28 17:54:21 +02:00
|
|
|
return units->distanceUnit();
|
2019-03-13 01:25:53 +01:00
|
|
|
case TableAxisVariable::path_depth:
|
|
|
|
|
case TableAxisVariable::normalized_voltage:
|
|
|
|
|
case TableAxisVariable::unknown:
|
2018-09-28 17:54:21 +02:00
|
|
|
return units->scalarUnit();
|
|
|
|
|
}
|
|
|
|
|
// Prevent warnings from lame compilers.
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|