You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1641 lines
48 KiB
1641 lines
48 KiB
/**CFile**********************************************************************
|
|
|
|
FileName [dddmpStoreMisc.c]
|
|
|
|
PackageName [dddmp]
|
|
|
|
Synopsis [Functions to write out bdds to file in prefixed
|
|
and in Blif form.]
|
|
|
|
Description [Functions to write out bdds to file.
|
|
BDDs are represended on file in text format.
|
|
Each node is stored as a multiplexer in a prefix notation format for
|
|
the prefix notation file or in PLA format for the blif file.
|
|
]
|
|
|
|
Author [Gianpiero Cabodi and Stefano Quer]
|
|
|
|
Copyright [
|
|
Copyright (c) 2004 by Politecnico di Torino.
|
|
All Rights Reserved. This software is for educational purposes only.
|
|
Permission is given to academic institutions to use, copy, and modify
|
|
this software and its documentation provided that this introductory
|
|
message is not removed, that this software and its documentation is
|
|
used for the institutions' internal research and educational purposes,
|
|
and that no monies are exchanged. No guarantee is expressed or implied
|
|
by the distribution of this code.
|
|
Send bug-reports and/or questions to:
|
|
{gianpiero.cabodi,stefano.quer}@polito.it.
|
|
]
|
|
|
|
******************************************************************************/
|
|
|
|
#include "dddmpInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**AutomaticStart*************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int DddmpCuddDdArrayStorePrefix(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, char *modelName, FILE *fp);
|
|
static int DddmpCuddDdArrayStorePrefixBody(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, FILE *fp);
|
|
static int DddmpCuddDdArrayStorePrefixStep(DdManager * ddMgr, DdNode * f, FILE * fp, st_table * visited, char ** names);
|
|
static int DddmpCuddDdArrayStoreBlif(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, char *modelName, FILE *fp);
|
|
static int DddmpCuddDdArrayStoreBlifBody(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, FILE *fp);
|
|
static int DddmpCuddDdArrayStoreBlifStep(DdManager *ddMgr, DdNode *f, FILE *fp, st_table *visited, char **names);
|
|
static int DddmpCuddDdArrayStoreSmv(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, char *modelName, FILE *fp);
|
|
static int DddmpCuddDdArrayStoreSmvBody(DdManager *ddMgr, int n, DdNode **f, char **inputNames, char **outputNames, FILE *fp);
|
|
static int DddmpCuddDdArrayStoreSmvStep(DdManager * ddMgr, DdNode * f, FILE * fp, st_table * visited, char ** names);
|
|
|
|
/**AutomaticEnd***************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a prefix notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStorePrefix.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddStore]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddStorePrefix (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nRoots /* IN: Number of BDD roots */,
|
|
DdNode *f /* IN: BDD root to be stored */,
|
|
char **inputNames /* IN: Array of variable names */,
|
|
char **outputNames /* IN: Array of root names */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fileName /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
DdNode *tmpArray[1];
|
|
|
|
tmpArray[0] = f;
|
|
|
|
retValue = Dddmp_cuddBddArrayStorePrefix (ddMgr, 1, tmpArray,
|
|
inputNames, outputNames, modelName, fileName, fp);
|
|
|
|
return (retValue);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a prefix notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStorePrefix.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddArrayStore]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddArrayStorePrefix (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nroots /* IN: number of output BDD roots to be stored */,
|
|
DdNode **f /* IN: array of BDD roots to be stored */,
|
|
char **inputNames /* IN: array of variable names (or NULL) */,
|
|
char **outputNames /* IN: array of root names (or NULL) */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fname /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
int fileToClose = 0;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
int retValueBis;
|
|
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* Check if File needs to be opened in the proper mode.
|
|
*/
|
|
|
|
if (fp == NULL) {
|
|
fp = fopen (fname, "w");
|
|
Dddmp_CheckAndGotoLabel (fp==NULL, "Error opening file.",
|
|
failure);
|
|
fileToClose = 1;
|
|
}
|
|
|
|
retValue = DddmpCuddDdArrayStorePrefix (ddMgr, nroots, f,
|
|
inputNames, outputNames, modelName, fp);
|
|
|
|
if (fileToClose) {
|
|
fclose (fp);
|
|
}
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return (retValue);
|
|
|
|
failure:
|
|
return (DDDMP_FAILURE);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a Blif/Exlif notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStoreBlif.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddStorePrefix]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddStoreBlif (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nRoots /* IN: Number of BDD roots */,
|
|
DdNode *f /* IN: BDD root to be stored */,
|
|
char **inputNames /* IN: Array of variable names */,
|
|
char **outputNames /* IN: Array of root names */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fileName /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
DdNode *tmpArray[1];
|
|
|
|
tmpArray[0] = f;
|
|
|
|
retValue = Dddmp_cuddBddArrayStoreBlif (ddMgr, 1, tmpArray,
|
|
inputNames, outputNames, modelName, fileName, fp);
|
|
|
|
return (retValue);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a Blif/Exlif notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStoreBLif.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddArrayStorePrefix]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddArrayStoreBlif (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nroots /* IN: number of output BDD roots to be stored */,
|
|
DdNode **f /* IN: array of BDD roots to be stored */,
|
|
char **inputNames /* IN: array of variable names (or NULL) */,
|
|
char **outputNames /* IN: array of root names (or NULL) */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fname /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
int fileToClose = 0;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
int retValueBis;
|
|
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* Check if File needs to be opened in the proper mode.
|
|
*/
|
|
|
|
if (fp == NULL) {
|
|
fp = fopen (fname, "w");
|
|
Dddmp_CheckAndGotoLabel (fp==NULL, "Error opening file.",
|
|
failure);
|
|
fileToClose = 1;
|
|
}
|
|
|
|
retValue = DddmpCuddDdArrayStoreBlif (ddMgr, nroots, f,
|
|
inputNames, outputNames, modelName, fp);
|
|
|
|
if (fileToClose) {
|
|
fclose (fp);
|
|
}
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return (retValue);
|
|
|
|
failure:
|
|
return (DDDMP_FAILURE);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a prefix notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStorePrefix.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddStore]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddStoreSmv (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nRoots /* IN: Number of BDD roots */,
|
|
DdNode *f /* IN: BDD root to be stored */,
|
|
char **inputNames /* IN: Array of variable names */,
|
|
char **outputNames /* IN: Array of root names */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fileName /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
DdNode *tmpArray[1];
|
|
|
|
tmpArray[0] = f;
|
|
|
|
retValue = Dddmp_cuddBddArrayStoreSmv (ddMgr, 1, tmpArray,
|
|
inputNames, outputNames, modelName, fileName, fp);
|
|
|
|
return (retValue);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a dump file representing the argument BDD in
|
|
a prefix notation.]
|
|
|
|
Description [Dumps the argument BDD to file.
|
|
Dumping is done through Dddmp_cuddBddArrayStorePrefix.
|
|
A dummy array of 1 BDD root is used for this purpose.
|
|
]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Dddmp_cuddBddArrayStore]
|
|
|
|
******************************************************************************/
|
|
|
|
int
|
|
Dddmp_cuddBddArrayStoreSmv (
|
|
DdManager *ddMgr /* IN: DD Manager */,
|
|
int nroots /* IN: number of output BDD roots to be stored */,
|
|
DdNode **f /* IN: array of BDD roots to be stored */,
|
|
char **inputNames /* IN: array of variable names (or NULL) */,
|
|
char **outputNames /* IN: array of root names (or NULL) */,
|
|
char *modelName /* IN: Model Name */,
|
|
char *fname /* IN: File name */,
|
|
FILE *fp /* IN: File pointer to the store file */
|
|
)
|
|
{
|
|
int retValue;
|
|
int fileToClose = 0;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
int retValueBis;
|
|
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* Check if File needs to be opened in the proper mode.
|
|
*/
|
|
|
|
if (fp == NULL) {
|
|
fp = fopen (fname, "w");
|
|
Dddmp_CheckAndGotoLabel (fp==NULL, "Error opening file.",
|
|
failure);
|
|
fileToClose = 1;
|
|
}
|
|
|
|
retValue = DddmpCuddDdArrayStoreSmv (ddMgr, nroots, f,
|
|
inputNames, outputNames, modelName, fp);
|
|
|
|
if (fileToClose) {
|
|
fclose (fp);
|
|
}
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
#ifndef __alpha__
|
|
retValueBis = Cudd_DebugCheck (ddMgr);
|
|
if (retValueBis == 1) {
|
|
fprintf (stderr, "Inconsistency Found During BDD Store.\n");
|
|
fflush (stderr);
|
|
} else {
|
|
if (retValueBis == CUDD_OUT_OF_MEM) {
|
|
fprintf (stderr, "Out of Memory During BDD Store.\n");
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return (retValue);
|
|
|
|
failure:
|
|
return (DDDMP_FAILURE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Internal function to writes a dump file representing the
|
|
argument BDD in a prefix notation.]
|
|
|
|
Description [One multiplexer is written for each BDD node.
|
|
It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file
|
|
system full, or an ADD with constants different from 0 and 1).
|
|
It does not close the file: This is the caller responsibility.
|
|
It uses a minimal unique subset of the hexadecimal address of a node as
|
|
name for it.
|
|
If the argument inputNames is non-null, it is assumed to hold the
|
|
pointers to the names of the inputs. Similarly for outputNames.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
Comments (COMMENT) are added at the beginning of the description to
|
|
describe inputs and outputs of the design.
|
|
A buffer (BUF) is add on the output to cope with complemented functions.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [DddmpCuddDdArrayStoreBlif]
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStorePrefix (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
char *modelName /* IN: Model name (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
DdNode *support = NULL;
|
|
DdNode *scan;
|
|
int *sorted = NULL;
|
|
int nVars = ddMgr->size;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Build a bit array with the support of f. */
|
|
sorted = ALLOC(int, nVars);
|
|
if (sorted == NULL) {
|
|
ddMgr->errorCode = CUDD_MEMORY_OUT;
|
|
Dddmp_CheckAndGotoLabel (1, "Allocation Error.", failure);
|
|
}
|
|
for (i = 0; i < nVars; i++) {
|
|
sorted[i] = 0;
|
|
}
|
|
|
|
/* Take the union of the supports of each output function. */
|
|
support = Cudd_VectorSupport(ddMgr,f,n);
|
|
Dddmp_CheckAndGotoLabel (support==NULL,
|
|
"Error in function Cudd_VectorSupport.", failure);
|
|
cuddRef(support);
|
|
scan = support;
|
|
while (!cuddIsConstant(scan)) {
|
|
sorted[scan->index] = 1;
|
|
scan = cuddT(scan);
|
|
}
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
/* so that we do not try to free it in case of failure */
|
|
support = NULL;
|
|
|
|
/* Write the header (.model .inputs .outputs). */
|
|
if (modelName == NULL) {
|
|
retValue = fprintf (fp, "(COMMENT - model name: Unknown )\n");
|
|
} else {
|
|
retValue = fprintf (fp, "(COMMENT - model name: %s )\n", modelName);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
retValue = fprintf(fp, "(COMMENT - input names: ");
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
/* Write the input list by scanning the support array. */
|
|
for (i = 0; i < nVars; i++) {
|
|
if (sorted[i]) {
|
|
if (inputNames == NULL) {
|
|
retValue = fprintf(fp," inNode%d", i);
|
|
} else {
|
|
retValue = fprintf(fp," %s", inputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
}
|
|
FREE(sorted);
|
|
sorted = NULL;
|
|
retValue = fprintf(fp, " )\n");
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
/* Write the .output line. */
|
|
retValue = fprintf(fp,"(COMMENT - output names: ");
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
if (outputNames == NULL) {
|
|
retValue = fprintf (fp," outNode%d", i);
|
|
} else {
|
|
retValue = fprintf (fp," %s", outputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
retValue = fprintf(fp, " )\n");
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
|
|
retValue = DddmpCuddDdArrayStorePrefixBody (ddMgr, n, f, inputNames,
|
|
outputNames, fp);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error in function DddmpCuddDdArrayStorePrefixBody.", failure);
|
|
|
|
return(1);
|
|
|
|
failure:
|
|
if (sorted != NULL) {
|
|
FREE(sorted);
|
|
}
|
|
if (support != NULL) {
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Internal function to writes a dump file representing the
|
|
argument BDD in a prefix notation. Writes the body of the file.]
|
|
|
|
Description [One multiplexer is written for each BDD node.
|
|
It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file
|
|
system full, or an ADD with constants different from 0 and 1).
|
|
It does not close the file: This is the caller responsibility.
|
|
It uses a minimal unique subset of the hexadecimal address of a node as
|
|
name for it.
|
|
If the argument inputNames is non-null, it is assumed to hold the
|
|
pointers to the names of the inputs. Similarly for outputNames.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [DddmpCuddDdArrayStoreBlif]
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStorePrefixBody (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
st_table *visited = NULL;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Initialize symbol table for visited nodes. */
|
|
visited = st_init_table(st_ptrcmp, st_ptrhash);
|
|
Dddmp_CheckAndGotoLabel (visited==NULL,
|
|
"Error if function st_init_table.", failure);
|
|
|
|
/* Call the function that really gets the job done. */
|
|
for (i = 0; i < n; i++) {
|
|
retValue = DddmpCuddDdArrayStorePrefixStep (ddMgr, Cudd_Regular(f[i]),
|
|
fp, visited, inputNames);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error if function DddmpCuddDdArrayStorePrefixStep.", failure);
|
|
}
|
|
|
|
/* To account for the possible complement on the root,
|
|
** we put either a buffer or an inverter at the output of
|
|
** the multiplexer representing the top node.
|
|
*/
|
|
for (i=0; i<n; i++) {
|
|
if (outputNames == NULL) {
|
|
retValue = fprintf (fp, "(BUF outNode%d ", i);
|
|
} else {
|
|
retValue = fprintf (fp, "(BUF %s ", outputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
|
|
if (Cudd_IsComplement(f[i])) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "(NOT node%lx))\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "(NOT node%x))\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
} else {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "node%lx)\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "node%x)\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
|
|
st_free_table (visited);
|
|
|
|
return(1);
|
|
|
|
failure:
|
|
if (visited != NULL) st_free_table(visited);
|
|
return(0);
|
|
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the recursive step of
|
|
DddmpCuddDdArrayStorePrefixBody.]
|
|
|
|
Description [Performs the recursive step of
|
|
DddmpCuddDdArrayStorePrefixBody.
|
|
Traverses the BDD f and writes a multiplexer-network description to the
|
|
file pointed by fp.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
f is assumed to be a regular pointer and the function guarantees this
|
|
assumption in the recursive calls.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStorePrefixStep (
|
|
DdManager * ddMgr,
|
|
DdNode * f,
|
|
FILE * fp,
|
|
st_table * visited,
|
|
char ** names
|
|
)
|
|
{
|
|
DdNode *T, *E;
|
|
int retValue;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
assert(!Cudd_IsComplement(f));
|
|
#endif
|
|
|
|
/* If already visited, nothing to do. */
|
|
if (st_is_member(visited, (char *) f) == 1) {
|
|
return(1);
|
|
}
|
|
|
|
/* Check for abnormal condition that should never happen. */
|
|
if (f == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Mark node as visited. */
|
|
if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM) {
|
|
return(0);
|
|
}
|
|
|
|
/* Check for special case: If constant node, generate constant 1. */
|
|
if (f == DD_ONE (ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp,
|
|
"(OR node%lx vss vdd)\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp,
|
|
"(OR node%x vss vdd)\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check whether this is an ADD. We deal with 0-1 ADDs, but not
|
|
* with the general case.
|
|
*/
|
|
|
|
if (f == DD_ZERO(ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp,
|
|
"(AND node%lx vss vdd)\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp,
|
|
"(AND node%x vss vdd)\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
if (cuddIsConstant(f)) {
|
|
return(0);
|
|
}
|
|
|
|
/* Recursive calls. */
|
|
T = cuddT(f);
|
|
retValue = DddmpCuddDdArrayStorePrefixStep (ddMgr,T,fp,visited,names);
|
|
if (retValue != 1) {
|
|
return(retValue);
|
|
}
|
|
E = Cudd_Regular(cuddE(f));
|
|
retValue = DddmpCuddDdArrayStorePrefixStep (ddMgr,E,fp,visited,names);
|
|
if (retValue != 1) {
|
|
return(retValue);
|
|
}
|
|
|
|
/* Write multiplexer taking complement arc into account. */
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "(OR node%lx (AND ",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "(OR node%x (AND ",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
if (names != NULL) {
|
|
retValue = fprintf(fp, "%s ", names[f->index]);
|
|
} else {
|
|
retValue = fprintf(fp, "inNode%d ", f->index);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "node%lx) (AND (NOT ",
|
|
(unsigned long) T / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "node%x) (AND (NOT ",
|
|
(unsigned) T / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
if (names != NULL) {
|
|
retValue = fprintf (fp, "%s", names[f->index]);
|
|
} else {
|
|
retValue = fprintf (fp, "inNode%d", f->index);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf (fp, ") (NOT node%lx)))\n",
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf (fp, ") node%lx))\n",
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode));
|
|
}
|
|
#else
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf (fp, ") (NOT node%x)))\n",
|
|
(unsigned) E / (unsigned) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf (fp, ") node%x))\n",
|
|
(unsigned) E / (unsigned) sizeof(DdNode));
|
|
}
|
|
#endif
|
|
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a blif file representing the argument BDDs.]
|
|
|
|
Description [Writes a blif file representing the argument BDDs as a
|
|
network of multiplexers. One multiplexer is written for each BDD
|
|
node. It returns 1 in case of success; 0 otherwise (e.g.,
|
|
out-of-memory, file system full, or an ADD with constants different
|
|
from 0 and 1).
|
|
DddmpCuddDdArrayStoreBlif does not close the file: This is the
|
|
caller responsibility.
|
|
DddmpCuddDdArrayStoreBlif uses a minimal unique subset of
|
|
the hexadecimal address of a node as name for it. If the argument
|
|
inames is non-null, it is assumed to hold the pointers to the names
|
|
of the inputs. Similarly for outputNames.
|
|
It prefixes the string "NODE" to each nome to have "regular" names
|
|
for each elements.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [DddmpCuddDdArrayStoreBlifBody,Cudd_DumpBlif]
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreBlif (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
char *modelName /* IN: Model name (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
DdNode *support = NULL;
|
|
DdNode *scan;
|
|
int *sorted = NULL;
|
|
int nVars = ddMgr->size;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Build a bit array with the support of f. */
|
|
sorted = ALLOC (int, nVars);
|
|
if (sorted == NULL) {
|
|
ddMgr->errorCode = CUDD_MEMORY_OUT;
|
|
Dddmp_CheckAndGotoLabel (1, "Allocation Error.", failure);
|
|
}
|
|
for (i = 0; i < nVars; i++) {
|
|
sorted[i] = 0;
|
|
}
|
|
|
|
/* Take the union of the supports of each output function. */
|
|
support = Cudd_VectorSupport(ddMgr,f,n);
|
|
Dddmp_CheckAndGotoLabel (support==NULL,
|
|
"Error in function Cudd_VectorSupport.", failure);
|
|
cuddRef(support);
|
|
scan = support;
|
|
while (!cuddIsConstant(scan)) {
|
|
sorted[scan->index] = 1;
|
|
scan = cuddT(scan);
|
|
}
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
support = NULL;
|
|
/* so that we do not try to free it in case of failure */
|
|
|
|
/* Write the header (.model .inputs .outputs). */
|
|
if (modelName == NULL) {
|
|
retValue = fprintf(fp,".model DD\n.inputs");
|
|
} else {
|
|
retValue = fprintf(fp,".model %s\n.inputs", modelName);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
/* Write the input list by scanning the support array. */
|
|
for (i = 0; i < nVars; i++) {
|
|
if (sorted[i]) {
|
|
if (inputNames == NULL || (inputNames[i] == NULL)) {
|
|
retValue = fprintf(fp," inNode%d", i);
|
|
} else {
|
|
retValue = fprintf(fp," %s", inputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
}
|
|
FREE(sorted);
|
|
sorted = NULL;
|
|
|
|
/* Write the .output line. */
|
|
retValue = fprintf(fp,"\n.outputs");
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
for (i = 0; i < n; i++) {
|
|
if (outputNames == NULL || (outputNames[i] == NULL)) {
|
|
retValue = fprintf(fp," outNode%d", i);
|
|
} else {
|
|
retValue = fprintf(fp," %s", outputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
retValue = fprintf(fp,"\n");
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
|
|
retValue = DddmpCuddDdArrayStoreBlifBody(ddMgr, n, f, inputNames,
|
|
outputNames, fp);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error if function DddmpCuddDdArrayStoreBlifBody.", failure);
|
|
|
|
/* Write trailer and return. */
|
|
retValue = fprintf (fp, ".end\n");
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
|
|
return(1);
|
|
|
|
failure:
|
|
if (sorted != NULL) {
|
|
FREE(sorted);
|
|
}
|
|
if (support != NULL) {
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Writes a blif body representing the argument BDDs.]
|
|
|
|
Description [Writes a blif body representing the argument BDDs as a
|
|
network of multiplexers. One multiplexer is written for each BDD
|
|
node. It returns 1 in case of success; 0 otherwise (e.g.,
|
|
out-of-memory, file system full, or an ADD with constants different
|
|
from 0 and 1).
|
|
DddmpCuddDdArrayStoreBlif does not close the file: This is the
|
|
caller responsibility.
|
|
DddmpCuddDdArrayStoreBlif uses a minimal unique subset of
|
|
the hexadecimal address of a node as name for it. If the argument
|
|
inputNames is non-null, it is assumed to hold the pointers to the names
|
|
of the inputs. Similarly for outputNames. This function prints out only
|
|
.names part.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreBlifBody (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
st_table *visited = NULL;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Initialize symbol table for visited nodes. */
|
|
visited = st_init_table(st_ptrcmp, st_ptrhash);
|
|
Dddmp_CheckAndGotoLabel (visited==NULL,
|
|
"Error if function st_init_table.", failure);
|
|
|
|
/* Call the function that really gets the job done. */
|
|
for (i = 0; i < n; i++) {
|
|
retValue = DddmpCuddDdArrayStoreBlifStep (ddMgr, Cudd_Regular(f[i]),
|
|
fp, visited, inputNames);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error if function DddmpCuddDdArrayStoreBlifStep.", failure);
|
|
}
|
|
|
|
/*
|
|
* To account for the possible complement on the root,
|
|
* we put either a buffer or an inverter at the output of
|
|
* the multiplexer representing the top node.
|
|
*/
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (outputNames == NULL) {
|
|
retValue = fprintf(fp,
|
|
#if SIZEOF_VOID_P == 8
|
|
".names node%lx outNode%d\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode), i);
|
|
#else
|
|
".names node%x outNode%d\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode), i);
|
|
#endif
|
|
} else {
|
|
retValue = fprintf(fp,
|
|
#if SIZEOF_VOID_P == 8
|
|
".names node%lx %s\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode), outputNames[i]);
|
|
#else
|
|
".names node%x %s\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode), outputNames[i]);
|
|
#endif
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
if (Cudd_IsComplement(f[i])) {
|
|
retValue = fprintf(fp,"0 1\n");
|
|
} else {
|
|
retValue = fprintf(fp,"1 1\n");
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
|
|
st_free_table(visited);
|
|
return(1);
|
|
|
|
failure:
|
|
if (visited != NULL) {
|
|
st_free_table(visited);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the recursive step of DddmpCuddDdArrayStoreBlif.]
|
|
|
|
Description [Performs the recursive step of DddmpCuddDdArrayStoreBlif.
|
|
Traverses the BDD f and writes a multiplexer-network description to
|
|
the file pointed by fp in blif format.
|
|
f is assumed to be a regular pointer and DddmpCuddDdArrayStoreBlifStep
|
|
guarantees this assumption in the recursive calls.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreBlifStep (
|
|
DdManager *ddMgr,
|
|
DdNode *f,
|
|
FILE *fp,
|
|
st_table *visited,
|
|
char **names
|
|
)
|
|
{
|
|
DdNode *T, *E;
|
|
int retValue;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
assert(!Cudd_IsComplement(f));
|
|
#endif
|
|
|
|
/* If already visited, nothing to do. */
|
|
if (st_is_member(visited, (char *) f) == 1) {
|
|
return(1);
|
|
}
|
|
|
|
/* Check for abnormal condition that should never happen. */
|
|
if (f == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Mark node as visited. */
|
|
if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM) {
|
|
return(0);
|
|
}
|
|
|
|
/* Check for special case: If constant node, generate constant 1. */
|
|
if (f == DD_ONE(ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf(fp, ".names node%lx\n1\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf(fp, ".names node%x\n1\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/* Check whether this is an ADD. We deal with 0-1 ADDs, but not
|
|
** with the general case.
|
|
*/
|
|
if (f == DD_ZERO(ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf(fp, ".names node%lx\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf(fp, ".names node%x\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
if (cuddIsConstant(f)) {
|
|
return(0);
|
|
}
|
|
|
|
/* Recursive calls. */
|
|
T = cuddT(f);
|
|
retValue = DddmpCuddDdArrayStoreBlifStep(ddMgr,T,fp,visited,names);
|
|
if (retValue != 1) return(retValue);
|
|
E = Cudd_Regular(cuddE(f));
|
|
retValue = DddmpCuddDdArrayStoreBlifStep(ddMgr,E,fp,visited,names);
|
|
if (retValue != 1) return(retValue);
|
|
|
|
/* Write multiplexer taking complement arc into account. */
|
|
if (names != NULL) {
|
|
retValue = fprintf(fp,".names %s", names[f->index]);
|
|
} else {
|
|
retValue = fprintf(fp,".names inNode%d", f->index);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf(fp," node%lx node%lx node%lx\n11- 1\n0-0 1\n",
|
|
(unsigned long) T / (unsigned long) sizeof(DdNode),
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode),
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf(fp," node%lx node%lx node%lx\n11- 1\n0-1 1\n",
|
|
(unsigned long) T / (unsigned long) sizeof(DdNode),
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode),
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
}
|
|
#else
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf(fp," node%x node%x node%x\n11- 1\n0-0 1\n",
|
|
(unsigned) T / (unsigned) sizeof(DdNode),
|
|
(unsigned) E / (unsigned) sizeof(DdNode),
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf(fp," node%x node%x node%x\n11- 1\n0-1 1\n",
|
|
(unsigned) T / (unsigned) sizeof(DdNode),
|
|
(unsigned) E / (unsigned) sizeof(DdNode),
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
}
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Internal function to writes a dump file representing the
|
|
argument BDD in a SMV notation.]
|
|
|
|
Description [One multiplexer is written for each BDD node.
|
|
It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file
|
|
system full, or an ADD with constants different from 0 and 1).
|
|
It does not close the file: This is the caller responsibility.
|
|
It uses a minimal unique subset of the hexadecimal address of a node as
|
|
name for it.
|
|
If the argument inputNames is non-null, it is assumed to hold the
|
|
pointers to the names of the inputs. Similarly for outputNames.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
Comments (COMMENT) are added at the beginning of the description to
|
|
describe inputs and outputs of the design.
|
|
A buffer (BUF) is add on the output to cope with complemented functions.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [DddmpCuddDdArrayStoreBlif]
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreSmv (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
char *modelName /* IN: Model name (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
DdNode *support = NULL;
|
|
DdNode *scan;
|
|
int *sorted = NULL;
|
|
int nVars = ddMgr->size;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Build a bit array with the support of f. */
|
|
sorted = ALLOC(int, nVars);
|
|
if (sorted == NULL) {
|
|
ddMgr->errorCode = CUDD_MEMORY_OUT;
|
|
Dddmp_CheckAndGotoLabel (1, "Allocation Error.", failure);
|
|
}
|
|
for (i = 0; i < nVars; i++) {
|
|
sorted[i] = 0;
|
|
}
|
|
|
|
/* Take the union of the supports of each output function. */
|
|
support = Cudd_VectorSupport(ddMgr,f,n);
|
|
Dddmp_CheckAndGotoLabel (support==NULL,
|
|
"Error in function Cudd_VectorSupport.", failure);
|
|
cuddRef(support);
|
|
scan = support;
|
|
while (!cuddIsConstant(scan)) {
|
|
sorted[scan->index] = 1;
|
|
scan = cuddT(scan);
|
|
}
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
/* so that we do not try to free it in case of failure */
|
|
support = NULL;
|
|
|
|
/* Write the header */
|
|
if (modelName == NULL) {
|
|
retValue = fprintf (fp, "MODULE main -- Unknown\n");
|
|
} else {
|
|
retValue = fprintf (fp, "MODULE main -- %s\n", modelName);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
retValue = fprintf(fp, "IVAR\n");
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
/* Write the input list by scanning the support array. */
|
|
for (i=0; i<nVars; i++) {
|
|
if (sorted[i]) {
|
|
if (inputNames == NULL) {
|
|
retValue = fprintf (fp, " inNode%d : boolean;\n", i);
|
|
} else {
|
|
retValue = fprintf (fp, " %s : boolean;\n", inputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
}
|
|
FREE(sorted);
|
|
sorted = NULL;
|
|
|
|
retValue = fprintf (fp, "\nDEFINE\n");
|
|
|
|
retValue = DddmpCuddDdArrayStoreSmvBody (ddMgr, n, f, inputNames,
|
|
outputNames, fp);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error in function DddmpCuddDdArrayStoreSmvBody.", failure);
|
|
|
|
return(1);
|
|
|
|
failure:
|
|
if (sorted != NULL) {
|
|
FREE(sorted);
|
|
}
|
|
if (support != NULL) {
|
|
Cudd_RecursiveDeref(ddMgr,support);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Internal function to writes a dump file representing the
|
|
argument BDD in a SMV notation. Writes the body of the file.]
|
|
|
|
Description [One multiplexer is written for each BDD node.
|
|
It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file
|
|
system full, or an ADD with constants different from 0 and 1).
|
|
It does not close the file: This is the caller responsibility.
|
|
It uses a minimal unique subset of the hexadecimal address of a node as
|
|
name for it.
|
|
If the argument inputNames is non-null, it is assumed to hold the
|
|
pointers to the names of the inputs. Similarly for outputNames.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [DddmpCuddDdArrayStoreBlif]
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreSmvBody (
|
|
DdManager *ddMgr /* IN: Manager */,
|
|
int n /* IN: Number of output nodes to be dumped */,
|
|
DdNode **f /* IN: Array of output nodes to be dumped */,
|
|
char **inputNames /* IN: Array of input names (or NULL) */,
|
|
char **outputNames /* IN: Array of output names (or NULL) */,
|
|
FILE *fp /* IN: Pointer to the dump file */
|
|
)
|
|
{
|
|
st_table *visited = NULL;
|
|
int retValue;
|
|
int i;
|
|
|
|
/* Initialize symbol table for visited nodes. */
|
|
visited = st_init_table(st_ptrcmp, st_ptrhash);
|
|
Dddmp_CheckAndGotoLabel (visited==NULL,
|
|
"Error if function st_init_table.", failure);
|
|
|
|
/* Call the function that really gets the job done. */
|
|
for (i = 0; i < n; i++) {
|
|
retValue = DddmpCuddDdArrayStoreSmvStep (ddMgr, Cudd_Regular(f[i]),
|
|
fp, visited, inputNames);
|
|
Dddmp_CheckAndGotoLabel (retValue==0,
|
|
"Error if function DddmpCuddDdArrayStoreSmvStep.", failure);
|
|
}
|
|
|
|
/*
|
|
* To account for the possible complement on the root,
|
|
* we put either a buffer or an inverter at the output of
|
|
* the multiplexer representing the top node.
|
|
*/
|
|
|
|
for (i=0; i<n; i++) {
|
|
if (outputNames == NULL) {
|
|
retValue = fprintf (fp, "outNode%d := ", i);
|
|
} else {
|
|
retValue = fprintf (fp, "%s := ", outputNames[i]);
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
|
|
if (Cudd_IsComplement(f[i])) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "!node%lx\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "!node%x\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
} else {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "node%lx\n",
|
|
(unsigned long) f[i] / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "node%x\n",
|
|
(unsigned) f[i] / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
}
|
|
Dddmp_CheckAndGotoLabel (retValue==EOF,
|
|
"Error during file store.", failure);
|
|
}
|
|
|
|
st_free_table (visited);
|
|
|
|
return(1);
|
|
|
|
failure:
|
|
if (visited != NULL) st_free_table(visited);
|
|
return(0);
|
|
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the recursive step of
|
|
DddmpCuddDdArrayStoreSmvBody.]
|
|
|
|
Description [Performs the recursive step of
|
|
DddmpCuddDdArrayStoreSmvBody.
|
|
Traverses the BDD f and writes a multiplexer-network description to the
|
|
file pointed by fp.
|
|
For each BDD node of function f, variable v, then child T, and else
|
|
child E it stores:
|
|
f = v * T + v' * E
|
|
that is
|
|
(OR f (AND v T) (AND (NOT v) E))
|
|
If E is a complemented child this results in the following
|
|
(OR f (AND v T) (AND (NOT v) (NOT E)))
|
|
f is assumed to be a regular pointer and the function guarantees this
|
|
assumption in the recursive calls.
|
|
]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
|
|
static int
|
|
DddmpCuddDdArrayStoreSmvStep (
|
|
DdManager * ddMgr,
|
|
DdNode * f,
|
|
FILE * fp,
|
|
st_table * visited,
|
|
char ** names
|
|
)
|
|
{
|
|
DdNode *T, *E;
|
|
int retValue;
|
|
|
|
#ifdef DDDMP_DEBUG
|
|
assert(!Cudd_IsComplement(f));
|
|
#endif
|
|
|
|
/* If already visited, nothing to do. */
|
|
if (st_is_member(visited, (char *) f) == 1) {
|
|
return(1);
|
|
}
|
|
|
|
/* Check for abnormal condition that should never happen. */
|
|
if (f == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Mark node as visited. */
|
|
if (st_insert(visited, (char *) f, NULL) == ST_OUT_OF_MEM) {
|
|
return(0);
|
|
}
|
|
|
|
/* Check for special case: If constant node, generate constant 1. */
|
|
if (f == DD_ONE (ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp,
|
|
"node%lx := 1;\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp,
|
|
"node%x := 1;\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check whether this is an ADD. We deal with 0-1 ADDs, but not
|
|
* with the general case.
|
|
*/
|
|
|
|
if (f == DD_ZERO(ddMgr)) {
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp,
|
|
"node%lx := 0;\n",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp,
|
|
"node%x := 0;\n",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
if (cuddIsConstant(f)) {
|
|
return(0);
|
|
}
|
|
|
|
/* Recursive calls. */
|
|
T = cuddT(f);
|
|
retValue = DddmpCuddDdArrayStoreSmvStep (ddMgr,T,fp,visited,names);
|
|
if (retValue != 1) {
|
|
return(retValue);
|
|
}
|
|
E = Cudd_Regular(cuddE(f));
|
|
retValue = DddmpCuddDdArrayStoreSmvStep (ddMgr,E,fp,visited,names);
|
|
if (retValue != 1) {
|
|
return(retValue);
|
|
}
|
|
|
|
/* Write multiplexer taking complement arc into account. */
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "node%lx := ",
|
|
(unsigned long) f / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "node%x := ",
|
|
(unsigned) f / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
if (names != NULL) {
|
|
retValue = fprintf(fp, "%s ", names[f->index]);
|
|
} else {
|
|
retValue = fprintf(fp, "inNode%d ", f->index);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
retValue = fprintf (fp, "& node%lx | ",
|
|
(unsigned long) T / (unsigned long) sizeof(DdNode));
|
|
#else
|
|
retValue = fprintf (fp, "& node%x | ",
|
|
(unsigned) T / (unsigned) sizeof(DdNode));
|
|
#endif
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
if (names != NULL) {
|
|
retValue = fprintf (fp, "!%s ", names[f->index]);
|
|
} else {
|
|
retValue = fprintf (fp, "!inNode%d ", f->index);
|
|
}
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
}
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf (fp, "& !node%lx\n",
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf (fp, "& node%lx\n",
|
|
(unsigned long) E / (unsigned long) sizeof(DdNode));
|
|
}
|
|
#else
|
|
if (Cudd_IsComplement(cuddE(f))) {
|
|
retValue = fprintf (fp, "& !node%x\n",
|
|
(unsigned) E / (unsigned) sizeof(DdNode));
|
|
} else {
|
|
retValue = fprintf (fp, "& node%x\n",
|
|
(unsigned) E / (unsigned) sizeof(DdNode));
|
|
}
|
|
#endif
|
|
|
|
if (retValue == EOF) {
|
|
return(0);
|
|
} else {
|
|
return(1);
|
|
}
|
|
}
|
|
|