require CUDD

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2024-07-17 14:19:49 -07:00
parent 2da2064852
commit e3a1fd792c
8 changed files with 27 additions and 449 deletions

View File

@ -28,7 +28,6 @@ project(STA VERSION 2.6.0
LANGUAGES CXX
)
option(USE_CUDD "Use CUDD BDD package" ON)
option(CUDD_DIR "CUDD BDD package directory")
option(USE_TCL_READLINE "Use TCL readliine package" ON)
option(USE_SANITIZE "Compile with santize address enabled")
@ -371,14 +370,12 @@ find_package(Eigen3 REQUIRED)
#
# Locate CUDD bdd package.
#
set(CUDD 0)
if (USE_CUDD)
find_library(CUDD_LIB
find_library(CUDD_LIB
NAME cudd
PATHS ${CUDD_DIR}
PATH_SUFFIXES lib lib/cudd cudd/.libs
)
if (CUDD_LIB)
if (CUDD_LIB)
message(STATUS "CUDD library: ${CUDD_LIB}")
get_filename_component(CUDD_LIB_DIR "${CUDD_LIB}" PATH)
get_filename_component(CUDD_LIB_PARENT1 "${CUDD_LIB_DIR}" PATH)
@ -387,14 +384,11 @@ if (USE_CUDD)
if (CUDD_HEADER)
get_filename_component(CUDD_INCLUDE "${CUDD_HEADER}" PATH)
message(STATUS "CUDD header: ${CUDD_HEADER}")
# Referenced by StaConfig.hh.cmake
set(CUDD 1)
else()
message(STATUS "CUDD header: not found")
endif()
else()
else()
message(STATUS "CUDD library: not found")
endif()
endif()
if("${SSTA}" STREQUAL "")
@ -517,6 +511,7 @@ target_link_libraries(OpenSTA
Eigen3::Eigen
${TCL_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${CUDD_LIB}
)
if (TCL_READLINE_LIBRARY)
@ -527,9 +522,7 @@ if (ZLIB_LIBRARIES)
target_link_libraries(OpenSTA ${ZLIB_LIBRARIES})
endif()
if (CUDD_LIB)
target_link_libraries(OpenSTA ${CUDD_LIB})
endif()
target_link_libraries(OpenSTA )
target_include_directories(OpenSTA
PUBLIC

View File

@ -103,9 +103,9 @@ External library dependencies:
```
Ubuntu Macos license
eigen 3.4.0 3.4.0 MPL2 required
cudd 3.0.0 3.0.0 BSD required
tclreadline 2.3.8 2.3.8 BSD optional
zLib 1.2.5 1.2.8 zlib optional
cudd 3.0.0 3.0.0 BSD optional
```
The [TCL readline library](https://tclreadline.sourceforge.net/tclreadline.html)

View File

@ -7,8 +7,9 @@ Release 2.6.0 2024/07/??
-------------------------
The version of c++ used by OpenSTA is now 17.
The Cudd BBD packager is now required.
The USE_CUDD and USE_TCL_READLINE options default to ON.
The USE_TCL_READLINE option defaults to ON.
Release 2.5.0 2024/01/17
-------------------------

View File

@ -18,16 +18,10 @@
#include <map>
#include "cudd.h"
#include "StaState.hh"
#include "LibertyClass.hh"
#if CUDD
#include "cudd.h"
#else
struct DdNode;
struct DdManager;
#endif
namespace sta {
typedef std::map<const LibertyPort*, DdNode*> BddPortVarMap;

View File

@ -502,8 +502,6 @@ Power::clockGatePins(const Instance *inst,
////////////////////////////////////////////////////////////////
#if CUDD
PwrActivity
Power::evalActivity(FuncExpr *expr,
const Instance *inst)
@ -609,112 +607,6 @@ Power::evalBddActivity(DdNode *bdd,
return activity;
}
#else
PwrActivity
Power::evalActivity(FuncExpr *expr,
const Instance *inst)
{
return evalActivity(expr, inst, nullptr, true);
}
// Eval activity thru expr.
// With cofactor_port eval the positive/negative cofactor of expr wrt cofactor_port.
PwrActivity
Power::evalActivity(FuncExpr *expr,
const Instance *inst,
const LibertyPort *cofactor_port,
bool cofactor_positive)
{
switch (expr->op()) {
case FuncExpr::op_port: {
LibertyPort *port = expr->port();
if (port == cofactor_port) {
if (cofactor_positive)
return PwrActivity(0.0, 1.0, PwrActivityOrigin::constant);
else
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
}
if (port->direction()->isInternal())
return findSeqActivity(inst, port);
else {
Pin *pin = findLinkPin(inst, port);
if (pin) {
PwrActivity activity = findActivity(pin);
activity.setOrigin(PwrActivityOrigin::propagated);
return activity;
}
}
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
}
case FuncExpr::op_not: {
PwrActivity activity1 = evalActivity(expr->left(), inst,
cofactor_port, cofactor_positive);
return PwrActivity(activity1.activity(),
1.0 - activity1.duty(),
PwrActivityOrigin::propagated);
}
case FuncExpr::op_or: {
PwrActivity activity1 = evalActivity(expr->left(), inst,
cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float p1 = 1.0 - activity1.duty();
float p2 = 1.0 - activity2.duty();
return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1,
// d1 + d2 - d1 * d2
1.0 - p1 * p2,
PwrActivityOrigin::propagated);
}
case FuncExpr::op_and: {
PwrActivity activity1 = evalActivity(expr->left(), inst,
cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float p1 = activity1.duty();
float p2 = activity2.duty();
return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1,
p1 * p2,
PwrActivityOrigin::propagated);
}
case FuncExpr::op_xor: {
PwrActivity activity1 = evalActivity(expr->left(), inst,
cofactor_port, cofactor_positive);
PwrActivity activity2 = evalActivity(expr->right(), inst,
cofactor_port, cofactor_positive);
float d1 = activity1.duty();
float d2 = activity2.duty();
float p1 = d1 * (1.0 - d2);
float p2 = (1.0 - d1) * d2;
return PwrActivity(activity1.activity() + activity2.activity(),
p1 + p2,
PwrActivityOrigin::propagated);
}
case FuncExpr::op_one:
return PwrActivity(0.0, 1.0, PwrActivityOrigin::constant);
case FuncExpr::op_zero:
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
}
return PwrActivity();
}
// Eval activity of difference(expr) wrt cofactor port.
float
Power::evalDiffDuty(FuncExpr *expr,
LibertyPort *cofactor_port,
const Instance *inst)
{
// Activity of positive/negative cofactors.
PwrActivity pos = evalActivity(expr, inst, cofactor_port, true);
PwrActivity neg = evalActivity(expr, inst, cofactor_port, false);
// difference = xor(pos, neg).
float p1 = pos.duty() * (1.0 - neg.duty());
float p2 = neg.duty() * (1.0 - pos.duty());
return p1 + p2;
}
#endif // CUDD
////////////////////////////////////////////////////////////////
void

View File

@ -16,30 +16,11 @@
#include "Bdd.hh"
#include "cudd.h"
#include "StaConfig.hh"
#include "Report.hh"
#include "FuncExpr.hh"
#if CUDD
#include "cudd.h"
#else
#include <cstdint>
#define CUDD_UNIQUE_SLOTS 0
#define CUDD_CACHE_SLOTS 0
DdManager *Cudd_Init(int, int, int, int, int) { return nullptr; }
void Cudd_Quit(void *) {}
DdNode *Cudd_Not(void *) { return nullptr; }
DdNode *Cudd_bddOr(void *, void *, void *) { return nullptr; }
DdNode *Cudd_bddAnd(void *, void *, void *) { return nullptr; }
DdNode *Cudd_bddXor(void *, void *, void *) { return nullptr; }
DdNode *Cudd_ReadOne(void *) { return nullptr; }
DdNode *Cudd_ReadLogicZero(void *) { return nullptr; }
DdNode *Cudd_bddNewVar(void *) { return nullptr; }
int Cudd_NodeReadIndex(void *) { return 0;}
void Cudd_Ref(void *) {}
void Cudd_RecursiveDeref(void *, void *) {}
#endif
namespace sta {
Bdd::Bdd(const StaState *sta) :

View File

@ -16,7 +16,9 @@
#include "Sim.hh"
#include "StaConfig.hh" // CUDD
// https://davidkebo.com/cudd
#include "cudd.h"
#include "Error.hh"
#include "Mutex.hh"
#include "Debug.hh"
@ -32,14 +34,6 @@
#include "Sdc.hh"
#include "Graph.hh"
#if CUDD
// https://davidkebo.com/cudd
#include "cudd.h"
#else
#define Cudd_Init(ignore1, ignore2, ignore3, ignore4, ignore5) nullptr
#define Cudd_Quit(ignore1)
#endif
namespace sta {
static LogicValue
@ -69,8 +63,6 @@ Sim::~Sim()
delete observer_;
}
#if CUDD
TimingSense
Sim::functionSense(const FuncExpr *expr,
const Pin *input_pin,
@ -159,279 +151,6 @@ Sim::funcBddSim(const FuncExpr *expr,
return bdd;
}
#else
// No CUDD.
static LogicValue
logicOr(LogicValue value1,
LogicValue value2)
{
static LogicValue logic_or[5][5] =
{{LogicValue::zero, LogicValue::one, LogicValue::unknown, LogicValue::unknown, LogicValue::unknown},
{LogicValue::one, LogicValue::one, LogicValue::one, LogicValue::one, LogicValue::one},
{LogicValue::unknown,LogicValue::one, LogicValue::unknown, LogicValue::unknown, LogicValue::unknown},
{LogicValue::unknown,LogicValue::one, LogicValue::unknown, LogicValue::unknown, LogicValue::unknown},
{LogicValue::unknown,LogicValue::one, LogicValue::unknown, LogicValue::unknown, LogicValue::unknown}};
return logic_or[int(value1)][int(value2)];
}
static LogicValue
logicAnd(LogicValue value1,
LogicValue value2)
{
static LogicValue logic_and[5][5] =
{{LogicValue::zero,LogicValue::zero, LogicValue::zero, LogicValue::zero, LogicValue::zero},
{LogicValue::zero,LogicValue::one, LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::zero,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::zero,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::zero,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown}};
return logic_and[int(value1)][int(value2)];
}
static LogicValue
logicXor(LogicValue value1,
LogicValue value2)
{
static LogicValue logic_xor[5][5]=
{{LogicValue::zero, LogicValue::one, LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::one, LogicValue::zero, LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::unknown,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::unknown,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown},
{LogicValue::unknown,LogicValue::unknown,LogicValue::unknown,LogicValue::unknown, LogicValue::unknown}};
return logic_xor[int(value1)][int(value2)];
}
static TimingSense
senseNot(TimingSense sense)
{
static TimingSense sense_not[5] = {TimingSense::negative_unate,
TimingSense::positive_unate,
TimingSense::non_unate,
TimingSense::none,
TimingSense::unknown};
return sense_not[int(sense)];
}
static TimingSense
senseAndOr(TimingSense sense1,
TimingSense sense2)
{
static TimingSense sense_and_or[5][5] =
{{TimingSense::positive_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::positive_unate, TimingSense::unknown},
{TimingSense::non_unate, TimingSense::negative_unate,
TimingSense::non_unate, TimingSense::negative_unate, TimingSense::unknown},
{TimingSense::non_unate, TimingSense::non_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::unknown},
{TimingSense::positive_unate, TimingSense::negative_unate,
TimingSense::non_unate, TimingSense::none, TimingSense::unknown},
{TimingSense::unknown, TimingSense::unknown,
TimingSense::unknown, TimingSense::non_unate, TimingSense::unknown}};
return sense_and_or[int(sense1)][int(sense2)];
}
static TimingSense
senseXor(TimingSense sense1,
TimingSense sense2)
{
static TimingSense xor_sense[5][5] =
{{TimingSense::non_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::non_unate, TimingSense::unknown},
{TimingSense::non_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::non_unate, TimingSense::unknown},
{TimingSense::non_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::non_unate, TimingSense::unknown},
{TimingSense::non_unate, TimingSense::non_unate,
TimingSense::non_unate, TimingSense::none, TimingSense::unknown},
{TimingSense::unknown, TimingSense::unknown,
TimingSense::unknown, TimingSense::unknown, TimingSense::unknown}};
return xor_sense[int(sense1)][int(sense2)];
}
TimingSense
Sim::functionSense(const FuncExpr *expr,
const Pin *input_pin,
const Instance *inst)
{
TimingSense sense = TimingSense::none;
LogicValue value = LogicValue::unknown;
functionSense(expr, input_pin, inst, sense, value);
return sense;
}
void
Sim::functionSense(const FuncExpr *expr,
const Pin *input_pin,
const Instance *inst,
// return values
TimingSense &sense,
LogicValue &value) const
{
switch (expr->op()) {
case FuncExpr::op_port: {
Pin *pin = network_->findPin(inst, expr->port());
if (pin) {
if (pin == input_pin)
sense = TimingSense::positive_unate;
else
sense = TimingSense::none;
value = logicValue(pin);
}
else {
sense = TimingSense::none;
value = LogicValue::unknown;
}
break;
}
case FuncExpr::op_not: {
TimingSense sense1;
LogicValue value1;
functionSense(expr->left(), input_pin, inst, sense1, value1);
if (value1 == LogicValue::zero) {
sense = TimingSense::none;
value = LogicValue::one;
}
else if (value1 == LogicValue::one) {
sense = TimingSense::none;
value = LogicValue::zero;
}
else {
sense = senseNot(sense1);
value = LogicValue::unknown;
}
break;
}
case FuncExpr::op_or: {
TimingSense sense1, sense2;
LogicValue value1, value2;
functionSense(expr->left(), input_pin, inst, sense1, value1);
functionSense(expr->right(), input_pin, inst, sense2, value2);
if (value1 == LogicValue::one || value2 == LogicValue::one) {
sense = TimingSense::none;
value = LogicValue::one;
}
else if (value1 == LogicValue::zero) {
sense = sense2;
value = value2;
}
else if (value2 == LogicValue::zero) {
sense = sense1;
value = value1;
}
else {
sense = senseAndOr(sense1, sense2);
value = LogicValue::unknown;
}
break;
}
case FuncExpr::op_and: {
TimingSense sense1, sense2;
LogicValue value1, value2;
functionSense(expr->left(), input_pin, inst, sense1, value1);
functionSense(expr->right(), input_pin, inst, sense2, value2);
if (value1 == LogicValue::zero || value2 == LogicValue::zero) {
sense = TimingSense::none;
value = LogicValue::zero;
}
else if (value1 == LogicValue::one) {
sense = sense2;
value = value2;
}
else if (value2 == LogicValue::one) {
sense = sense1;
value = value1;
}
else {
sense = senseAndOr(sense1, sense2);
value = LogicValue::unknown;
}
break;
}
case FuncExpr::op_xor: {
TimingSense sense1, sense2;
LogicValue value1, value2;
functionSense(expr->left(), input_pin, inst, sense1, value1);
functionSense(expr->right(), input_pin, inst, sense2, value2);
if ((value1 == LogicValue::zero && value2 == LogicValue::zero)
|| (value1 == LogicValue::one && value2 == LogicValue::one)) {
sense = TimingSense::none;
value = LogicValue::zero;
}
else if ((value1 == LogicValue::zero && value2 == LogicValue::one)
|| (value1 == LogicValue::one && value2 == LogicValue::zero)) {
sense = TimingSense::none;
value = LogicValue::one;
}
else if (value1 == LogicValue::zero) {
sense = sense2;
value = value2;
}
else if (value1 == LogicValue::one) {
sense = senseNot(sense2);
value = logicNot(value2);
}
else if (value2 == LogicValue::zero) {
sense = sense1;
value = value1;
}
else if (value2 == LogicValue::one) {
sense = senseNot(sense1);
value = logicNot(value1);
}
else {
sense = senseXor(sense1, sense2);
value = logicXor(value1, value2);
}
break;
}
case FuncExpr::op_one:
sense = TimingSense::none;
value = LogicValue::one;
break;
case FuncExpr::op_zero:
sense = TimingSense::none;
value = LogicValue::zero;
break;
}
}
LogicValue
Sim::evalExpr(const FuncExpr *expr,
const Instance *inst)
{
switch (expr->op()) {
case FuncExpr::op_port: {
LibertyPort *port = expr->port();
if (port) {
Pin *pin = network_->findPin(inst, port->name());
if (pin)
return logicValue(pin);
}
// Internal ports don't have instance pins.
return LogicValue::unknown;
}
case FuncExpr::op_not:
return logicNot(evalExpr(expr->left(), inst));
case FuncExpr::op_or:
return logicOr(evalExpr(expr->left(),inst),
evalExpr(expr->right(),inst));
case FuncExpr::op_and:
return logicAnd(evalExpr(expr->left(),inst),
evalExpr(expr->right(),inst));
case FuncExpr::op_xor:
return logicXor(evalExpr(expr->left(),inst),
evalExpr(expr->right(),inst));
case FuncExpr::op_one:
return LogicValue::one;
case FuncExpr::op_zero:
return LogicValue::zero;
}
// Prevent warnings from lame compilers.
return LogicValue::zero;
}
#endif // CUDD
static LogicValue
logicNot(LogicValue value)
{

View File

@ -4,8 +4,6 @@
#cmakedefine ZLIB_FOUND
#define CUDD ${CUDD}
#define SSTA ${SSTA}
#define TCL_READLINE ${TCL_READLINE}