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 LANGUAGES CXX
) )
option(USE_CUDD "Use CUDD BDD package" ON)
option(CUDD_DIR "CUDD BDD package directory") option(CUDD_DIR "CUDD BDD package directory")
option(USE_TCL_READLINE "Use TCL readliine package" ON) option(USE_TCL_READLINE "Use TCL readliine package" ON)
option(USE_SANITIZE "Compile with santize address enabled") option(USE_SANITIZE "Compile with santize address enabled")
@ -371,30 +370,25 @@ find_package(Eigen3 REQUIRED)
# #
# Locate CUDD bdd package. # Locate CUDD bdd package.
# #
set(CUDD 0) find_library(CUDD_LIB
if (USE_CUDD) NAME cudd
find_library(CUDD_LIB PATHS ${CUDD_DIR}
NAME cudd PATH_SUFFIXES lib lib/cudd cudd/.libs
PATHS ${CUDD_DIR} )
PATH_SUFFIXES lib lib/cudd cudd/.libs if (CUDD_LIB)
) message(STATUS "CUDD library: ${CUDD_LIB}")
if (CUDD_LIB) get_filename_component(CUDD_LIB_DIR "${CUDD_LIB}" PATH)
message(STATUS "CUDD library: ${CUDD_LIB}") get_filename_component(CUDD_LIB_PARENT1 "${CUDD_LIB_DIR}" PATH)
get_filename_component(CUDD_LIB_DIR "${CUDD_LIB}" PATH) find_file(CUDD_HEADER cudd.h
get_filename_component(CUDD_LIB_PARENT1 "${CUDD_LIB_DIR}" PATH) PATHS ${CUDD_LIB_PARENT1} ${CUDD_LIB_PARENT1}/include ${CUDD_LIB_PARENT1}/include/cudd)
find_file(CUDD_HEADER cudd.h if (CUDD_HEADER)
PATHS ${CUDD_LIB_PARENT1} ${CUDD_LIB_PARENT1}/include ${CUDD_LIB_PARENT1}/include/cudd) get_filename_component(CUDD_INCLUDE "${CUDD_HEADER}" PATH)
if (CUDD_HEADER) message(STATUS "CUDD header: ${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") message(STATUS "CUDD header: not found")
endif() endif()
else()
message(STATUS "CUDD library: not found")
endif() endif()
if("${SSTA}" STREQUAL "") if("${SSTA}" STREQUAL "")
@ -517,6 +511,7 @@ target_link_libraries(OpenSTA
Eigen3::Eigen Eigen3::Eigen
${TCL_LIBRARY} ${TCL_LIBRARY}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${CUDD_LIB}
) )
if (TCL_READLINE_LIBRARY) if (TCL_READLINE_LIBRARY)
@ -527,9 +522,7 @@ if (ZLIB_LIBRARIES)
target_link_libraries(OpenSTA ${ZLIB_LIBRARIES}) target_link_libraries(OpenSTA ${ZLIB_LIBRARIES})
endif() endif()
if (CUDD_LIB) target_link_libraries(OpenSTA )
target_link_libraries(OpenSTA ${CUDD_LIB})
endif()
target_include_directories(OpenSTA target_include_directories(OpenSTA
PUBLIC PUBLIC

View File

@ -103,9 +103,9 @@ External library dependencies:
``` ```
Ubuntu Macos license Ubuntu Macos license
eigen 3.4.0 3.4.0 MPL2 required 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 tclreadline 2.3.8 2.3.8 BSD optional
zLib 1.2.5 1.2.8 zlib 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) 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 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 Release 2.5.0 2024/01/17
------------------------- -------------------------

View File

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

View File

@ -502,8 +502,6 @@ Power::clockGatePins(const Instance *inst,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
#if CUDD
PwrActivity PwrActivity
Power::evalActivity(FuncExpr *expr, Power::evalActivity(FuncExpr *expr,
const Instance *inst) const Instance *inst)
@ -609,112 +607,6 @@ Power::evalBddActivity(DdNode *bdd,
return activity; 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 void

View File

@ -16,30 +16,11 @@
#include "Bdd.hh" #include "Bdd.hh"
#include "cudd.h"
#include "StaConfig.hh" #include "StaConfig.hh"
#include "Report.hh" #include "Report.hh"
#include "FuncExpr.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 { namespace sta {
Bdd::Bdd(const StaState *sta) : Bdd::Bdd(const StaState *sta) :

View File

@ -16,7 +16,9 @@
#include "Sim.hh" #include "Sim.hh"
#include "StaConfig.hh" // CUDD // https://davidkebo.com/cudd
#include "cudd.h"
#include "Error.hh" #include "Error.hh"
#include "Mutex.hh" #include "Mutex.hh"
#include "Debug.hh" #include "Debug.hh"
@ -32,14 +34,6 @@
#include "Sdc.hh" #include "Sdc.hh"
#include "Graph.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 { namespace sta {
static LogicValue static LogicValue
@ -69,8 +63,6 @@ Sim::~Sim()
delete observer_; delete observer_;
} }
#if CUDD
TimingSense TimingSense
Sim::functionSense(const FuncExpr *expr, Sim::functionSense(const FuncExpr *expr,
const Pin *input_pin, const Pin *input_pin,
@ -159,279 +151,6 @@ Sim::funcBddSim(const FuncExpr *expr,
return bdd; 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 static LogicValue
logicNot(LogicValue value) logicNot(LogicValue value)
{ {

View File

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