2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, 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/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
//
|
|
|
|
|
// The origin of this software must not be misrepresented; you must not
|
|
|
|
|
// claim that you wrote the original software.
|
|
|
|
|
//
|
|
|
|
|
// Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
|
//
|
|
|
|
|
// This notice may not be removed or altered from any source distribution.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "FuncExpr.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "StringUtil.hh"
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "Network.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makePort(LibertyPort *port)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_port, nullptr, nullptr, port);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeNot(FuncExpr *expr)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_not, expr, nullptr, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeAnd(FuncExpr *left,
|
|
|
|
|
FuncExpr *right)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_and, left, right, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeOr(FuncExpr *left,
|
|
|
|
|
FuncExpr *right)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_or, left, right, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeXor(FuncExpr *left,
|
|
|
|
|
FuncExpr *right)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_xor, left, right, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeZero()
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_zero, nullptr, nullptr, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::makeOne()
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return new FuncExpr(op_one, nullptr, nullptr, nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr::FuncExpr(Operator op,
|
|
|
|
|
FuncExpr *left,
|
|
|
|
|
FuncExpr *right,
|
|
|
|
|
LibertyPort *port) :
|
|
|
|
|
op_(op),
|
|
|
|
|
left_(left),
|
|
|
|
|
right_(right),
|
|
|
|
|
port_(port)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FuncExpr::deleteSubexprs()
|
|
|
|
|
{
|
|
|
|
|
if (left_)
|
|
|
|
|
left_->deleteSubexprs();
|
|
|
|
|
if (right_)
|
|
|
|
|
right_->deleteSubexprs();
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-20 01:06:06 +02:00
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::copy()
|
|
|
|
|
{
|
|
|
|
|
FuncExpr *left = left_ ? left_->copy() : nullptr;
|
|
|
|
|
FuncExpr *right = right_ ? right_->copy() : nullptr;
|
|
|
|
|
return new FuncExpr(op_, left, right, port_);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
LibertyPort *
|
|
|
|
|
FuncExpr::port() const
|
|
|
|
|
{
|
|
|
|
|
if (op_ == op_port)
|
|
|
|
|
return port_;
|
|
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Protect against null sub-expressions caused by unknown port refs.
|
|
|
|
|
TimingSense
|
|
|
|
|
FuncExpr::portTimingSense(const LibertyPort *port) const
|
|
|
|
|
{
|
|
|
|
|
TimingSense left_sense, right_sense;
|
|
|
|
|
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case op_port:
|
|
|
|
|
if (port == port_)
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::positive_unate;
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::none;
|
2018-09-28 17:54:21 +02:00
|
|
|
case op_not:
|
|
|
|
|
if (left_) {
|
|
|
|
|
switch (left_->portTimingSense(port)) {
|
2019-03-13 01:25:53 +01:00
|
|
|
case TimingSense::positive_unate:
|
|
|
|
|
return TimingSense::negative_unate;
|
|
|
|
|
case TimingSense::negative_unate:
|
|
|
|
|
return TimingSense::positive_unate;
|
|
|
|
|
case TimingSense::non_unate:
|
|
|
|
|
return TimingSense::non_unate;
|
|
|
|
|
case TimingSense::none:
|
|
|
|
|
return TimingSense::none;
|
|
|
|
|
case TimingSense::unknown:
|
|
|
|
|
return TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
case op_or:
|
|
|
|
|
case op_and:
|
2019-03-13 01:25:53 +01:00
|
|
|
left_sense = TimingSense::unknown;
|
|
|
|
|
right_sense = TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (left_)
|
|
|
|
|
left_sense = left_->portTimingSense(port);
|
|
|
|
|
if (right_)
|
|
|
|
|
right_sense = right_->portTimingSense(port);
|
|
|
|
|
|
|
|
|
|
if (left_sense == right_sense)
|
|
|
|
|
return left_sense;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (left_sense == TimingSense::non_unate
|
|
|
|
|
|| right_sense == TimingSense::non_unate
|
|
|
|
|
|| (left_sense == TimingSense::positive_unate
|
|
|
|
|
&& right_sense == TimingSense::negative_unate)
|
|
|
|
|
|| (left_sense == TimingSense::negative_unate
|
|
|
|
|
&& right_sense == TimingSense::positive_unate))
|
|
|
|
|
return TimingSense::non_unate;
|
|
|
|
|
else if (left_sense == TimingSense::none
|
|
|
|
|
|| left_sense == TimingSense::unknown)
|
2018-09-28 17:54:21 +02:00
|
|
|
return right_sense;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (right_sense == TimingSense::none
|
|
|
|
|
|| right_sense == TimingSense::unknown)
|
2018-09-28 17:54:21 +02:00
|
|
|
return left_sense;
|
|
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
case op_xor:
|
2019-03-13 01:25:53 +01:00
|
|
|
left_sense = TimingSense::unknown;
|
|
|
|
|
right_sense = TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (left_)
|
|
|
|
|
left_sense = left_->portTimingSense(port);
|
|
|
|
|
if (right_)
|
|
|
|
|
right_sense = right_->portTimingSense(port);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (left_sense == TimingSense::positive_unate
|
|
|
|
|
|| left_sense == TimingSense::negative_unate
|
|
|
|
|
|| left_sense == TimingSense::non_unate
|
|
|
|
|
|| right_sense == TimingSense::positive_unate
|
|
|
|
|
|| right_sense == TimingSense::negative_unate
|
|
|
|
|
|| right_sense == TimingSense::non_unate)
|
|
|
|
|
return TimingSense::non_unate;
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
case op_one:
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::none;
|
2018-09-28 17:54:21 +02:00
|
|
|
case op_zero:
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::none;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
// Prevent warnings from lame compilers.
|
2019-03-13 01:25:53 +01:00
|
|
|
return TimingSense::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
FuncExpr::asString() const
|
|
|
|
|
{
|
|
|
|
|
return asString(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
FuncExpr::asString(bool with_parens) const
|
|
|
|
|
{
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case op_port:
|
|
|
|
|
return port_->name();
|
|
|
|
|
case op_not: {
|
|
|
|
|
const char *left = left_->asString(true);
|
|
|
|
|
size_t left_length = strlen(left);
|
|
|
|
|
size_t length = left_length + 2;
|
|
|
|
|
char *result = makeTmpString(length);
|
|
|
|
|
char *ptr = result;
|
|
|
|
|
*ptr++ = '!';
|
|
|
|
|
strcpy(ptr, left);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
case op_or:
|
|
|
|
|
return asStringSubexpr(with_parens, '+');
|
|
|
|
|
case op_and:
|
|
|
|
|
return asStringSubexpr(with_parens, '*');
|
|
|
|
|
case op_xor:
|
|
|
|
|
return asStringSubexpr(with_parens, '^');
|
|
|
|
|
case op_one:
|
|
|
|
|
return "1";
|
|
|
|
|
case op_zero:
|
|
|
|
|
return "0";
|
|
|
|
|
default:
|
|
|
|
|
return "?";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
FuncExpr::asStringSubexpr(bool with_parens,
|
|
|
|
|
char op) const
|
|
|
|
|
{
|
|
|
|
|
const char *left = left_->asString(true);
|
|
|
|
|
const char *right = right_->asString(true);
|
|
|
|
|
size_t length = strlen(left) + 1 + strlen(right) + 1;
|
|
|
|
|
if (with_parens)
|
|
|
|
|
length += 2;
|
|
|
|
|
char *result = makeTmpString(length);
|
|
|
|
|
char *r = result;
|
|
|
|
|
if (with_parens)
|
|
|
|
|
*r++= '(';
|
|
|
|
|
stringAppend(r, left);
|
|
|
|
|
*r++ = op;
|
|
|
|
|
stringAppend(r, right);
|
|
|
|
|
if (with_parens)
|
|
|
|
|
*r++ = ')';
|
|
|
|
|
*r = '\0';
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
FuncExpr::bitSubExpr(int bit_offset)
|
|
|
|
|
{
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case op_port:
|
|
|
|
|
if (port_->hasMembers()) {
|
|
|
|
|
if (port_->size() == 1) {
|
|
|
|
|
LibertyPort *port = port_->findLibertyMember(0);
|
|
|
|
|
return makePort(port);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
LibertyPort *port = port_->findLibertyMember(bit_offset);
|
|
|
|
|
return makePort(port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
// Always copy so the subexpr doesn't share memory.
|
|
|
|
|
return makePort(port_);
|
|
|
|
|
case op_not:
|
|
|
|
|
return makeNot(left_->bitSubExpr(bit_offset));
|
|
|
|
|
case op_or:
|
|
|
|
|
return makeOr(left_->bitSubExpr(bit_offset),
|
|
|
|
|
right_->bitSubExpr(bit_offset));
|
|
|
|
|
case op_and:
|
|
|
|
|
return makeAnd(left_->bitSubExpr(bit_offset),
|
|
|
|
|
right_->bitSubExpr(bit_offset));
|
|
|
|
|
case op_xor:
|
|
|
|
|
return makeXor(left_->bitSubExpr(bit_offset),
|
|
|
|
|
right_->bitSubExpr(bit_offset));
|
|
|
|
|
case op_one:
|
|
|
|
|
case op_zero:
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
// Prevent warnings from lame compilers.
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FuncExpr::hasPort(const LibertyPort *port) const
|
|
|
|
|
{
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case op_port:
|
|
|
|
|
return (port_ == port);
|
|
|
|
|
case op_not:
|
|
|
|
|
return left_ && left_->hasPort(port);
|
|
|
|
|
case op_or:
|
|
|
|
|
case op_and:
|
|
|
|
|
case op_xor:
|
|
|
|
|
return (left_ && left_->hasPort(port))
|
|
|
|
|
|| (right_ && right_->hasPort(port));
|
|
|
|
|
case op_one:
|
|
|
|
|
case op_zero:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Prevent warnings from lame compilers.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FuncExpr::checkSize(LibertyPort *port)
|
|
|
|
|
{
|
|
|
|
|
return checkSize(port->size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FuncExpr::checkSize(size_t size)
|
|
|
|
|
{
|
|
|
|
|
size_t port_size;
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case op_port:
|
|
|
|
|
port_size = port_->size();
|
|
|
|
|
return !(port_size == size
|
|
|
|
|
|| port_size == 1);
|
|
|
|
|
case op_not:
|
|
|
|
|
return left_->checkSize(size);
|
|
|
|
|
case op_or:
|
|
|
|
|
case op_and:
|
|
|
|
|
case op_xor:
|
|
|
|
|
return left_->checkSize(size) || right_->checkSize(size);
|
|
|
|
|
case op_one:
|
|
|
|
|
case op_zero:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Prevent warnings from lame compilers.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FuncExpr *
|
|
|
|
|
funcExprNot(FuncExpr *expr)
|
|
|
|
|
{
|
|
|
|
|
if (expr->op() == FuncExpr::op_not) {
|
|
|
|
|
FuncExpr *not_expr = expr->left();
|
|
|
|
|
delete expr;
|
|
|
|
|
return not_expr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return FuncExpr::makeNot(expr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2024-02-27 18:00:48 +01:00
|
|
|
FuncExprPortIterator::FuncExprPortIterator(const FuncExpr *expr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
findPorts(expr);
|
|
|
|
|
iter_.init(ports_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2024-02-27 18:00:48 +01:00
|
|
|
FuncExprPortIterator::findPorts(const FuncExpr *expr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (expr) {
|
|
|
|
|
if (expr->op() == FuncExpr::op_port)
|
|
|
|
|
ports_.insert(expr->port());
|
|
|
|
|
else {
|
|
|
|
|
findPorts(expr->left());
|
|
|
|
|
findPorts(expr->right());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FuncExpr::equiv(const FuncExpr *expr1,
|
|
|
|
|
const FuncExpr *expr2)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (expr1 == nullptr && expr2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return true;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (expr1 != nullptr && expr2 != nullptr
|
2018-09-28 17:54:21 +02:00
|
|
|
&& expr1->op() == expr2->op()) {
|
|
|
|
|
switch (expr1->op()) {
|
|
|
|
|
case FuncExpr::op_port:
|
|
|
|
|
return LibertyPort::equiv(expr1->port(), expr2->port());
|
|
|
|
|
case FuncExpr::op_not:
|
|
|
|
|
return equiv(expr1->left(), expr2->left());
|
|
|
|
|
default:
|
|
|
|
|
return equiv(expr1->left(), expr2->left())
|
|
|
|
|
&& equiv(expr1->right(), expr2->right());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FuncExpr::less(const FuncExpr *expr1,
|
|
|
|
|
const FuncExpr *expr2)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (expr1 != nullptr && expr2 != nullptr) {
|
2018-09-28 17:54:21 +02:00
|
|
|
Operator op1 = expr1->op();
|
|
|
|
|
Operator op2 = expr2->op();
|
|
|
|
|
if (op1 == op2) {
|
|
|
|
|
switch (expr1->op()) {
|
|
|
|
|
case FuncExpr::op_port:
|
|
|
|
|
return LibertyPort::less(expr1->port(), expr2->port());
|
|
|
|
|
case FuncExpr::op_not:
|
|
|
|
|
return less(expr1->left(), expr2->left());
|
|
|
|
|
default:
|
|
|
|
|
if (equiv(expr1->left(), expr2->left()))
|
|
|
|
|
return less(expr1->right(), expr2->right());
|
|
|
|
|
else
|
|
|
|
|
return less(expr1->left(), expr2->left());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return op1 < op2;
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (expr1 == nullptr && expr2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return false;
|
|
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return (expr1 == nullptr && expr2 != nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|