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.

2231 lines
56 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup nanotrav
  4. @brief Functions to read in a boolean network.
  5. @author Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "cuddInt.h"
  35. #include "bnet.h"
  36. /*---------------------------------------------------------------------------*/
  37. /* Constant declarations */
  38. /*---------------------------------------------------------------------------*/
  39. #define MAXLENGTH 131072
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /*---------------------------------------------------------------------------*/
  47. /* Variable declarations */
  48. /*---------------------------------------------------------------------------*/
  49. static char BuffLine[MAXLENGTH];
  50. static char *CurPos;
  51. static int newNameNumber = 0;
  52. /*---------------------------------------------------------------------------*/
  53. /* Macro declarations */
  54. /*---------------------------------------------------------------------------*/
  55. /** \cond */
  56. /*---------------------------------------------------------------------------*/
  57. /* Static function prototypes */
  58. /*---------------------------------------------------------------------------*/
  59. static char * readString (FILE *fp);
  60. static char ** readList (FILE *fp, int *n);
  61. static void printList (char **list, int n);
  62. static char ** bnetGenerateNewNames (st_table *hash, int n);
  63. static int bnetDumpReencodingLogic (DdManager *dd, char *mname, int noutputs, DdNode **outputs, char **inames, char **altnames, char **onames, FILE *fp);
  64. #if 0
  65. static int bnetBlifXnorTable (FILE *fp, int n);
  66. #endif
  67. static int bnetBlifWriteReencode (DdManager *dd, char *mname, char **inames, char **altnames, int *support, FILE *fp);
  68. static int * bnetFindVectorSupport (DdManager *dd, DdNode **list, int n);
  69. static int buildExorBDD (DdManager *dd, BnetNode *nd, st_table *hash, int params, int nodrop);
  70. static int buildMuxBDD (DdManager * dd, BnetNode * nd, st_table * hash, int params, int nodrop);
  71. static int bnetSetLevel (BnetNetwork *net);
  72. static int bnetLevelDFS (BnetNetwork *net, BnetNode *node);
  73. static BnetNode ** bnetOrderRoots (BnetNetwork *net, int *nroots);
  74. static int bnetLevelCompare (BnetNode **x, BnetNode **y);
  75. static int bnetDfsOrder (DdManager *dd, BnetNetwork *net, BnetNode *node);
  76. /** \endcond */
  77. /*---------------------------------------------------------------------------*/
  78. /* Definition of exported functions */
  79. /*---------------------------------------------------------------------------*/
  80. /**
  81. @brief Reads boolean network from blif file.
  82. @details A very restricted subset of blif is supported. Specifically:
  83. <ul>
  84. <li> The only directives recognized are:
  85. <ul>
  86. <li> .model
  87. <li> .inputs
  88. <li> .outputs
  89. <li> .latch
  90. <li> .names
  91. <li> .exdc
  92. <li> .wire_load_slope
  93. <li> .end
  94. </ul>
  95. <li> Latches must have an initial values and no other parameters
  96. specified.
  97. <li> Lines must not exceed MAXLENGTH-1 characters, and individual names must
  98. not exceed 1023 characters.
  99. </ul>
  100. Caveat emptor: There may be other limitations as well. One should
  101. check the syntax of the blif file with some other tool before relying
  102. on this parser.
  103. @return a pointer to the network if successful; NULL otherwise.
  104. @sideeffect None
  105. @see Bnet_PrintNetwork Bnet_FreeNetwork
  106. */
  107. BnetNetwork *
  108. Bnet_ReadNetwork(
  109. FILE * fp /**< pointer to the blif file */,
  110. int pr /**< verbosity level */)
  111. {
  112. char *savestring;
  113. char **list;
  114. int i, j, n;
  115. BnetNetwork *net;
  116. BnetNode *newnode;
  117. BnetNode *lastnode = NULL;
  118. BnetTabline *newline;
  119. BnetTabline *lastline;
  120. char ***latches = NULL;
  121. int maxlatches = 0;
  122. int exdc = 0;
  123. BnetNode *node;
  124. int count;
  125. /* Allocate network object and initialize symbol table. */
  126. net = ALLOC(BnetNetwork,1);
  127. if (net == NULL) goto failure;
  128. memset((char *) net, 0, sizeof(BnetNetwork));
  129. net->hash = st_init_table((st_compare_t) strcmp, st_strhash);
  130. if (net->hash == NULL) goto failure;
  131. savestring = readString(fp);
  132. if (savestring == NULL) goto failure;
  133. net->nlatches = 0;
  134. while (strcmp(savestring, ".model") == 0 ||
  135. strcmp(savestring, ".inputs") == 0 ||
  136. strcmp(savestring, ".outputs") == 0 ||
  137. strcmp(savestring, ".latch") == 0 ||
  138. strcmp(savestring, ".wire_load_slope") == 0 ||
  139. strcmp(savestring, ".exdc") == 0 ||
  140. strcmp(savestring, ".names") == 0 || strcmp(savestring,".end") == 0) {
  141. if (strcmp(savestring, ".model") == 0) {
  142. /* Read .model directive. */
  143. FREE(savestring);
  144. /* Read network name. */
  145. savestring = readString(fp);
  146. if (savestring == NULL) goto failure;
  147. if (savestring[0] == '.') {
  148. net->name = ALLOC(char, 1);
  149. if (net->name == NULL) goto failure;
  150. net->name[0] = '\0';
  151. } else {
  152. net->name = savestring;
  153. }
  154. } else if (strcmp(savestring, ".inputs") == 0) {
  155. /* Read .inputs directive. */
  156. FREE(savestring);
  157. /* Read input names. */
  158. list = readList(fp,&n);
  159. if (list == NULL) goto failure;
  160. if (pr > 2) printList(list,n);
  161. /* Expect at least one input. */
  162. if (n < 1) {
  163. (void) fprintf(stdout,"Empty input list.\n");
  164. goto failure;
  165. }
  166. if (exdc) {
  167. for (i = 0; i < n; i++)
  168. FREE(list[i]);
  169. FREE(list);
  170. savestring = readString(fp);
  171. if (savestring == NULL) goto failure;
  172. continue;
  173. }
  174. if (net->ninputs) {
  175. net->inputs = REALLOC(char *, net->inputs,
  176. (net->ninputs + n) * sizeof(char *));
  177. for (i = 0; i < n; i++)
  178. net->inputs[net->ninputs + i] = list[i];
  179. }
  180. else
  181. net->inputs = list;
  182. /* Create a node for each primary input. */
  183. for (i = 0; i < n; i++) {
  184. newnode = ALLOC(BnetNode,1);
  185. memset((char *) newnode, 0, sizeof(BnetNode));
  186. if (newnode == NULL) goto failure;
  187. newnode->name = list[i];
  188. newnode->inputs = NULL;
  189. newnode->type = BNET_INPUT_NODE;
  190. newnode->active = FALSE;
  191. newnode->nfo = 0;
  192. newnode->ninp = 0;
  193. newnode->f = NULL;
  194. newnode->polarity = 0;
  195. newnode->dd = NULL;
  196. newnode->next = NULL;
  197. if (lastnode == NULL) {
  198. net->nodes = newnode;
  199. } else {
  200. lastnode->next = newnode;
  201. }
  202. lastnode = newnode;
  203. }
  204. net->npis += n;
  205. net->ninputs += n;
  206. } else if (strcmp(savestring, ".outputs") == 0) {
  207. /* Read .outputs directive. We do not create nodes for the primary
  208. ** outputs, because the nodes will be created when the same names
  209. ** appear as outputs of some gates.
  210. */
  211. FREE(savestring);
  212. /* Read output names. */
  213. list = readList(fp,&n);
  214. if (list == NULL) goto failure;
  215. if (pr > 2) printList(list,n);
  216. if (n < 1) {
  217. (void) fprintf(stdout,"Empty .outputs list.\n");
  218. goto failure;
  219. }
  220. if (exdc) {
  221. for (i = 0; i < n; i++)
  222. FREE(list[i]);
  223. FREE(list);
  224. savestring = readString(fp);
  225. if (savestring == NULL) goto failure;
  226. continue;
  227. }
  228. if (net->noutputs) {
  229. net->outputs = REALLOC(char *, net->outputs,
  230. (net->noutputs + n) * sizeof(char *));
  231. for (i = 0; i < n; i++)
  232. net->outputs[net->noutputs + i] = list[i];
  233. } else {
  234. net->outputs = list;
  235. }
  236. net->npos += n;
  237. net->noutputs += n;
  238. } else if (strcmp(savestring,".wire_load_slope") == 0) {
  239. FREE(savestring);
  240. savestring = readString(fp);
  241. net->slope = savestring;
  242. } else if (strcmp(savestring,".latch") == 0) {
  243. FREE(savestring);
  244. newnode = ALLOC(BnetNode,1);
  245. if (newnode == NULL) goto failure;
  246. memset((char *) newnode, 0, sizeof(BnetNode));
  247. newnode->type = BNET_PRESENT_STATE_NODE;
  248. list = readList(fp,&n);
  249. if (list == NULL) goto failure;
  250. if (pr > 2) printList(list,n);
  251. /* Expect three names. */
  252. if (n != 3) {
  253. (void) fprintf(stdout,
  254. ".latch not followed by three tokens.\n");
  255. goto failure;
  256. }
  257. newnode->name = list[1];
  258. newnode->inputs = NULL;
  259. newnode->ninp = 0;
  260. newnode->f = NULL;
  261. newnode->active = FALSE;
  262. newnode->nfo = 0;
  263. newnode->polarity = 0;
  264. newnode->dd = NULL;
  265. newnode->next = NULL;
  266. if (lastnode == NULL) {
  267. net->nodes = newnode;
  268. } else {
  269. lastnode->next = newnode;
  270. }
  271. lastnode = newnode;
  272. /* Add next state variable to list. */
  273. if (maxlatches == 0) {
  274. maxlatches = 20;
  275. latches = ALLOC(char **,maxlatches);
  276. } else if (maxlatches <= net->nlatches) {
  277. maxlatches += 20;
  278. latches = REALLOC(char **,latches,maxlatches);
  279. }
  280. latches[net->nlatches] = list;
  281. net->nlatches++;
  282. savestring = readString(fp);
  283. if (savestring == NULL) goto failure;
  284. } else if (strcmp(savestring,".names") == 0) {
  285. FREE(savestring);
  286. newnode = ALLOC(BnetNode,1);
  287. memset((char *) newnode, 0, sizeof(BnetNode));
  288. if (newnode == NULL) goto failure;
  289. list = readList(fp,&n);
  290. if (list == NULL) goto failure;
  291. if (pr > 2) printList(list,n);
  292. /* Expect at least one name (the node output). */
  293. if (n < 1) {
  294. (void) fprintf(stdout,"Missing output name.\n");
  295. goto failure;
  296. }
  297. newnode->name = list[n-1];
  298. newnode->inputs = list;
  299. newnode->ninp = n-1;
  300. newnode->active = FALSE;
  301. newnode->nfo = 0;
  302. newnode->polarity = 0;
  303. if (newnode->ninp > 0) {
  304. newnode->type = BNET_INTERNAL_NODE;
  305. for (i = 0; i < net->noutputs; i++) {
  306. if (strcmp(net->outputs[i], newnode->name) == 0) {
  307. newnode->type = BNET_OUTPUT_NODE;
  308. break;
  309. }
  310. }
  311. } else {
  312. newnode->type = BNET_CONSTANT_NODE;
  313. }
  314. newnode->dd = NULL;
  315. newnode->next = NULL;
  316. if (lastnode == NULL) {
  317. net->nodes = newnode;
  318. } else {
  319. lastnode->next = newnode;
  320. }
  321. lastnode = newnode;
  322. /* Read node function. */
  323. newnode->f = NULL;
  324. if (exdc) {
  325. newnode->exdc_flag = 1;
  326. node = net->nodes;
  327. while (node) {
  328. if (node->type == BNET_OUTPUT_NODE &&
  329. strcmp(node->name, newnode->name) == 0) {
  330. node->exdc = newnode;
  331. break;
  332. }
  333. node = node->next;
  334. }
  335. }
  336. savestring = readString(fp);
  337. if (savestring == NULL) goto failure;
  338. lastline = NULL;
  339. while (savestring[0] != '.') {
  340. /* Reading a table line. */
  341. newline = ALLOC(BnetTabline,1);
  342. if (newline == NULL) goto failure;
  343. newline->next = NULL;
  344. if (lastline == NULL) {
  345. newnode->f = newline;
  346. } else {
  347. lastline->next = newline;
  348. }
  349. lastline = newline;
  350. if (newnode->type == BNET_INTERNAL_NODE ||
  351. newnode->type == BNET_OUTPUT_NODE) {
  352. newline->values = savestring;
  353. /* Read output 1 or 0. */
  354. savestring = readString(fp);
  355. if (savestring == NULL) goto failure;
  356. } else {
  357. newline->values = NULL;
  358. }
  359. if (savestring[0] == '0') newnode->polarity = 1;
  360. FREE(savestring);
  361. savestring = readString(fp);
  362. if (savestring == NULL) goto failure;
  363. }
  364. } else if (strcmp(savestring,".exdc") == 0) {
  365. FREE(savestring);
  366. exdc = 1;
  367. } else if (strcmp(savestring,".end") == 0) {
  368. FREE(savestring);
  369. break;
  370. }
  371. if ((!savestring) || savestring[0] != '.')
  372. savestring = readString(fp);
  373. if (savestring == NULL) goto failure;
  374. }
  375. /* Put nodes in symbol table. */
  376. newnode = net->nodes;
  377. while (newnode != NULL) {
  378. int retval = st_insert(net->hash,newnode->name,(char *) newnode);
  379. if (retval == ST_OUT_OF_MEM) {
  380. goto failure;
  381. } else if (retval == 1) {
  382. printf("Error: Multiple drivers for node %s\n", newnode->name);
  383. goto failure;
  384. } else {
  385. if (pr > 2) printf("Inserted %s\n",newnode->name);
  386. }
  387. newnode = newnode->next;
  388. }
  389. if (latches) {
  390. net->latches = latches;
  391. count = 0;
  392. net->outputs = REALLOC(char *, net->outputs,
  393. (net->noutputs + net->nlatches) * sizeof(char *));
  394. for (i = 0; i < net->nlatches; i++) {
  395. for (j = 0; j < net->noutputs; j++) {
  396. if (strcmp(latches[i][0], net->outputs[j]) == 0)
  397. break;
  398. }
  399. if (j < net->noutputs)
  400. continue;
  401. savestring = ALLOC(char, strlen(latches[i][0]) + 1);
  402. strcpy(savestring, latches[i][0]);
  403. net->outputs[net->noutputs + count] = savestring;
  404. count++;
  405. if (st_lookup(net->hash, savestring, (void **) &node)) {
  406. if (node->type == BNET_INTERNAL_NODE) {
  407. node->type = BNET_OUTPUT_NODE;
  408. }
  409. }
  410. }
  411. net->noutputs += count;
  412. net->inputs = REALLOC(char *, net->inputs,
  413. (net->ninputs + net->nlatches) * sizeof(char *));
  414. for (i = 0; i < net->nlatches; i++) {
  415. savestring = ALLOC(char, strlen(latches[i][1]) + 1);
  416. strcpy(savestring, latches[i][1]);
  417. net->inputs[net->ninputs + i] = savestring;
  418. }
  419. net->ninputs += net->nlatches;
  420. }
  421. /* Compute fanout counts. For each node in the linked list, fetch
  422. ** all its fanins using the symbol table, and increment the fanout of
  423. ** each fanin.
  424. */
  425. newnode = net->nodes;
  426. while (newnode != NULL) {
  427. BnetNode *auxnd;
  428. for (i = 0; i < newnode->ninp; i++) {
  429. if (!st_lookup(net->hash,newnode->inputs[i],(void **)&auxnd)) {
  430. (void) fprintf(stdout,"%s not driven\n", newnode->inputs[i]);
  431. goto failure;
  432. }
  433. auxnd->nfo++;
  434. }
  435. newnode = newnode->next;
  436. }
  437. if (!bnetSetLevel(net)) goto failure;
  438. return(net);
  439. failure:
  440. /* Here we should clean up the mess. */
  441. (void) fprintf(stdout,"Error in reading network from file.\n");
  442. return(NULL);
  443. } /* end of Bnet_ReadNetwork */
  444. /**
  445. @brief Prints to stdout a boolean network created by Bnet_ReadNetwork.
  446. @details Uses the blif format; this way, one can verify the
  447. equivalence of the input and the output with, say, sis.
  448. @sideeffect None
  449. @see Bnet_ReadNetwork
  450. */
  451. void
  452. Bnet_PrintNetwork(
  453. BnetNetwork * net /**< boolean network */)
  454. {
  455. BnetNode *nd;
  456. BnetTabline *tl;
  457. int i;
  458. if (net == NULL) return;
  459. (void) fprintf(stdout,".model %s\n", net->name);
  460. (void) fprintf(stdout,".inputs");
  461. printList(net->inputs,net->npis);
  462. (void) fprintf(stdout,".outputs");
  463. printList(net->outputs,net->npos);
  464. for (i = 0; i < net->nlatches; i++) {
  465. (void) fprintf(stdout,".latch");
  466. printList(net->latches[i],3);
  467. }
  468. nd = net->nodes;
  469. while (nd != NULL) {
  470. if (nd->type != BNET_INPUT_NODE && nd->type != BNET_PRESENT_STATE_NODE) {
  471. (void) fprintf(stdout,".names");
  472. for (i = 0; i < nd->ninp; i++) {
  473. (void) fprintf(stdout," %s",nd->inputs[i]);
  474. }
  475. (void) fprintf(stdout," %s\n",nd->name);
  476. tl = nd->f;
  477. while (tl != NULL) {
  478. if (tl->values != NULL) {
  479. (void) fprintf(stdout,"%s %d\n",tl->values,
  480. 1 - nd->polarity);
  481. } else {
  482. (void) fprintf(stdout,"%d\n", 1 - nd->polarity);
  483. }
  484. tl = tl->next;
  485. }
  486. }
  487. nd = nd->next;
  488. }
  489. (void) fprintf(stdout,".end\n");
  490. } /* end of Bnet_PrintNetwork */
  491. /**
  492. @brief Frees a boolean network created by Bnet_ReadNetwork.
  493. @sideeffect None
  494. @see Bnet_ReadNetwork
  495. */
  496. void
  497. Bnet_FreeNetwork(
  498. BnetNetwork * net)
  499. {
  500. BnetNode *node, *nextnode;
  501. BnetTabline *line, *nextline;
  502. int i;
  503. FREE(net->name);
  504. /* The input name strings are already pointed by the input nodes.
  505. ** Here we only need to free the latch names and the array that
  506. ** points to them.
  507. */
  508. for (i = 0; i < net->nlatches; i++) {
  509. FREE(net->inputs[net->npis + i]);
  510. }
  511. FREE(net->inputs);
  512. /* Free the output name strings and then the array pointing to them. */
  513. for (i = 0; i < net->noutputs; i++) {
  514. FREE(net->outputs[i]);
  515. }
  516. FREE(net->outputs);
  517. for (i = 0; i < net->nlatches; i++) {
  518. FREE(net->latches[i][0]);
  519. FREE(net->latches[i][1]);
  520. FREE(net->latches[i][2]);
  521. FREE(net->latches[i]);
  522. }
  523. if (net->nlatches) FREE(net->latches);
  524. node = net->nodes;
  525. while (node != NULL) {
  526. nextnode = node->next;
  527. if (node->type != BNET_PRESENT_STATE_NODE)
  528. FREE(node->name);
  529. for (i = 0; i < node->ninp; i++) {
  530. FREE(node->inputs[i]);
  531. }
  532. if (node->inputs != NULL) {
  533. FREE(node->inputs);
  534. }
  535. /* Free the function table. */
  536. line = node->f;
  537. while (line != NULL) {
  538. nextline = line->next;
  539. FREE(line->values);
  540. FREE(line);
  541. line = nextline;
  542. }
  543. FREE(node);
  544. node = nextnode;
  545. }
  546. st_free_table(net->hash);
  547. if (net->slope != NULL) FREE(net->slope);
  548. FREE(net);
  549. } /* end of Bnet_FreeNetwork */
  550. /**
  551. @brief Builds the %BDD for the function of a node.
  552. @details Builds the %BDD for the function of a node and stores a
  553. pointer to it in the dd field of the node itself. The reference count
  554. of the %BDD is incremented. If params is BNET_LOCAL_DD, then the %BDD is
  555. built in terms of the local inputs to the node; otherwise, if params
  556. is BNET_GLOBAL_DD, the %BDD is built in terms of the network primary
  557. inputs. To build the global %BDD of a node, the BDDs for its local
  558. inputs must exist. If that is not the case, Bnet_BuildNodeBDD
  559. recursively builds them. Likewise, to create the local %BDD for a node,
  560. the local inputs must have variables assigned to them. If that is not
  561. the case, Bnet_BuildNodeBDD recursively assigns variables to nodes.
  562. @return 1 in case of success; 0 otherwise.
  563. @sideeffect Sets the dd field of the node.
  564. */
  565. int
  566. Bnet_BuildNodeBDD(
  567. DdManager * dd /**< %DD manager */,
  568. BnetNode * nd /**< node of the boolean network */,
  569. st_table * hash /**< symbol table of the boolean network */,
  570. int params /**< type of %DD to be built */,
  571. int nodrop /**< retain the intermediate node DDs until the end */)
  572. {
  573. DdNode *func;
  574. BnetNode *auxnd;
  575. DdNode *tmp;
  576. DdNode *prod, *var;
  577. BnetTabline *line;
  578. int i;
  579. if (nd->dd != NULL) return(1);
  580. if (nd->type == BNET_CONSTANT_NODE) {
  581. if (nd->f == NULL) { /* constant 0 */
  582. func = Cudd_ReadLogicZero(dd);
  583. } else { /* either constant depending on the polarity */
  584. func = Cudd_ReadOne(dd);
  585. }
  586. Cudd_Ref(func);
  587. } else if (nd->type == BNET_INPUT_NODE ||
  588. nd->type == BNET_PRESENT_STATE_NODE) {
  589. if (nd->active == TRUE) { /* a variable is already associated: use it */
  590. func = Cudd_ReadVars(dd,nd->var);
  591. if (func == NULL) goto failure;
  592. } else { /* no variable associated: get a new one */
  593. func = Cudd_bddNewVar(dd);
  594. if (func == NULL) goto failure;
  595. nd->var = func->index;
  596. nd->active = TRUE;
  597. }
  598. Cudd_Ref(func);
  599. } else if (buildExorBDD(dd,nd,hash,params,nodrop)) {
  600. func = nd->dd;
  601. } else if (buildMuxBDD(dd,nd,hash,params,nodrop)) {
  602. func = nd->dd;
  603. } else { /* type == BNET_INTERNAL_NODE or BNET_OUTPUT_NODE */
  604. /* Initialize the sum to logical 0. */
  605. func = Cudd_ReadLogicZero(dd);
  606. Cudd_Ref(func);
  607. /* Build a term for each line of the table and add it to the
  608. ** accumulator (func).
  609. */
  610. line = nd->f;
  611. while (line != NULL) {
  612. #ifdef BNET_DEBUG
  613. (void) fprintf(stdout,"line = %s\n", line->values);
  614. #endif
  615. /* Initialize the product to logical 1. */
  616. prod = Cudd_ReadOne(dd);
  617. Cudd_Ref(prod);
  618. /* Scan the table line. */
  619. for (i = 0; i < nd->ninp; i++) {
  620. if (line->values[i] == '-') continue;
  621. if (!st_lookup(hash,nd->inputs[i],(void **)&auxnd)) {
  622. goto failure;
  623. }
  624. if (params == BNET_LOCAL_DD) {
  625. if (auxnd->active == FALSE) {
  626. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  627. goto failure;
  628. }
  629. }
  630. var = Cudd_ReadVars(dd,auxnd->var);
  631. if (var == NULL) goto failure;
  632. Cudd_Ref(var);
  633. if (line->values[i] == '0') {
  634. var = Cudd_Not(var);
  635. }
  636. } else { /* params == BNET_GLOBAL_DD */
  637. if (auxnd->dd == NULL) {
  638. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  639. goto failure;
  640. }
  641. }
  642. if (line->values[i] == '1') {
  643. var = auxnd->dd;
  644. } else { /* line->values[i] == '0' */
  645. var = Cudd_Not(auxnd->dd);
  646. }
  647. }
  648. tmp = Cudd_bddAnd(dd,prod,var);
  649. if (tmp == NULL) goto failure;
  650. Cudd_Ref(tmp);
  651. Cudd_IterDerefBdd(dd,prod);
  652. if (params == BNET_LOCAL_DD) {
  653. Cudd_IterDerefBdd(dd,var);
  654. }
  655. prod = tmp;
  656. }
  657. tmp = Cudd_bddOr(dd,func,prod);
  658. if (tmp == NULL) goto failure;
  659. Cudd_Ref(tmp);
  660. Cudd_IterDerefBdd(dd,func);
  661. Cudd_IterDerefBdd(dd,prod);
  662. func = tmp;
  663. line = line->next;
  664. }
  665. /* Associate a variable to this node if local BDDs are being
  666. ** built. This is done at the end, so that the primary inputs tend
  667. ** to get lower indices.
  668. */
  669. if (params == BNET_LOCAL_DD && nd->active == FALSE) {
  670. DdNode *auxfunc = Cudd_bddNewVar(dd);
  671. if (auxfunc == NULL) goto failure;
  672. Cudd_Ref(auxfunc);
  673. nd->var = auxfunc->index;
  674. nd->active = TRUE;
  675. Cudd_IterDerefBdd(dd,auxfunc);
  676. }
  677. }
  678. if (nd->polarity == 1) {
  679. nd->dd = Cudd_Not(func);
  680. } else {
  681. nd->dd = func;
  682. }
  683. if (params == BNET_GLOBAL_DD && nodrop == FALSE) {
  684. /* Decrease counters for all faninis.
  685. ** When count reaches 0, the DD is freed.
  686. */
  687. for (i = 0; i < nd->ninp; i++) {
  688. if (!st_lookup(hash,nd->inputs[i],(void **)&auxnd)) {
  689. goto failure;
  690. }
  691. auxnd->count--;
  692. if (auxnd->count == 0) {
  693. Cudd_IterDerefBdd(dd,auxnd->dd);
  694. if (auxnd->type == BNET_INTERNAL_NODE ||
  695. auxnd->type == BNET_CONSTANT_NODE) auxnd->dd = NULL;
  696. }
  697. }
  698. }
  699. return(1);
  700. failure:
  701. /* Here we should clean up the mess. */
  702. return(0);
  703. } /* end of Bnet_BuildNodeBDD */
  704. /**
  705. @brief Orders the %BDD variables by DFS.
  706. @return 1 in case of success; 0 otherwise.
  707. @sideeffect Uses the visited flags of the nodes.
  708. */
  709. int
  710. Bnet_DfsVariableOrder(
  711. DdManager * dd,
  712. BnetNetwork * net)
  713. {
  714. BnetNode **roots;
  715. BnetNode *node;
  716. int nroots;
  717. int i;
  718. roots = bnetOrderRoots(net,&nroots);
  719. if (roots == NULL) return(0);
  720. for (i = 0; i < nroots; i++) {
  721. if (!bnetDfsOrder(dd,net,roots[i])) {
  722. FREE(roots);
  723. return(0);
  724. }
  725. }
  726. /* Clear visited flags. */
  727. node = net->nodes;
  728. while (node != NULL) {
  729. node->visited = 0;
  730. node = node->next;
  731. }
  732. FREE(roots);
  733. return(1);
  734. } /* end of Bnet_DfsVariableOrder */
  735. /**
  736. @brief Writes the network BDDs to a file in dot, blif, or daVinci
  737. format.
  738. @details If "-" is passed as file name, the BDDs are dumped to the
  739. standard output.
  740. @return 1 in case of success; 0 otherwise.
  741. @sideeffect None
  742. */
  743. int
  744. Bnet_bddDump(
  745. DdManager * dd /**< %DD manager */,
  746. BnetNetwork * network /**< network whose BDDs should be dumped */,
  747. char * dfile /**< file name */,
  748. int dumpFmt /**< 0 -> dot */,
  749. int reencoded /**< whether variables have been reencoded */)
  750. {
  751. int noutputs;
  752. FILE *dfp = NULL;
  753. DdNode **outputs = NULL;
  754. char **inames = NULL;
  755. char **onames = NULL;
  756. char **altnames = NULL;
  757. BnetNode *node;
  758. int i;
  759. int retval = 0; /* 0 -> failure; 1 -> success */
  760. /* Open dump file. */
  761. if (strcmp(dfile, "-") == 0) {
  762. dfp = stdout;
  763. } else {
  764. dfp = fopen(dfile,"w");
  765. }
  766. if (dfp == NULL) goto endgame;
  767. /* Initialize data structures. */
  768. noutputs = network->noutputs;
  769. outputs = ALLOC(DdNode *,noutputs);
  770. if (outputs == NULL) goto endgame;
  771. onames = ALLOC(char *,noutputs);
  772. if (onames == NULL) goto endgame;
  773. inames = ALLOC(char *,Cudd_ReadSize(dd));
  774. if (inames == NULL) goto endgame;
  775. /* Find outputs and their names. */
  776. for (i = 0; i < network->nlatches; i++) {
  777. onames[i] = network->latches[i][0];
  778. if (!st_lookup(network->hash,network->latches[i][0],(void **)&node)) {
  779. goto endgame;
  780. }
  781. outputs[i] = node->dd;
  782. }
  783. for (i = 0; i < network->npos; i++) {
  784. onames[i + network->nlatches] = network->outputs[i];
  785. if (!st_lookup(network->hash,network->outputs[i],(void **)&node)) {
  786. goto endgame;
  787. }
  788. outputs[i + network->nlatches] = node->dd;
  789. }
  790. /* Find the input names. */
  791. for (i = 0; i < network->ninputs; i++) {
  792. if (!st_lookup(network->hash,network->inputs[i],(void **)&node)) {
  793. goto endgame;
  794. }
  795. inames[node->var] = network->inputs[i];
  796. }
  797. for (i = 0; i < network->nlatches; i++) {
  798. if (!st_lookup(network->hash,network->latches[i][1],(void **)&node)) {
  799. goto endgame;
  800. }
  801. inames[node->var] = network->latches[i][1];
  802. }
  803. if (reencoded == 1 && dumpFmt == 1) {
  804. altnames = bnetGenerateNewNames(network->hash,network->ninputs);
  805. if (altnames == NULL) {
  806. retval = 0;
  807. goto endgame;
  808. }
  809. retval = bnetDumpReencodingLogic(dd,network->name,noutputs,outputs,
  810. inames,altnames,onames,dfp);
  811. for (i = 0; i < network->ninputs; i++) {
  812. FREE(altnames[i]);
  813. }
  814. FREE(altnames);
  815. if (retval == 0) goto endgame;
  816. }
  817. /* Dump the BDDs. */
  818. if (dumpFmt == 1) {
  819. retval = Cudd_DumpBlif(dd,noutputs,outputs,
  820. (char const * const *) inames,
  821. (char const * const *) onames,
  822. network->name,dfp,0);
  823. } else if (dumpFmt == 2) {
  824. retval = Cudd_DumpDaVinci(dd,noutputs,outputs,
  825. (char const * const *) inames,
  826. (char const * const *) onames,dfp);
  827. } else if (dumpFmt == 3) {
  828. retval = Cudd_DumpDDcal(dd,noutputs,outputs,
  829. (char const * const *) inames,
  830. (char const * const *) onames,dfp);
  831. } else if (dumpFmt == 4) {
  832. retval = Cudd_DumpFactoredForm(dd,noutputs,outputs,
  833. (char const * const *) inames,
  834. (char const * const *) onames,dfp);
  835. } else if (dumpFmt == 5) {
  836. retval = Cudd_DumpBlif(dd,noutputs,outputs,
  837. (char const * const *) inames,
  838. (char const * const *) onames,
  839. network->name,dfp,1);
  840. } else {
  841. retval = Cudd_DumpDot(dd,noutputs,outputs,
  842. (char const * const *) inames,
  843. (char const * const *) onames,dfp);
  844. }
  845. endgame:
  846. if (dfp != stdout && dfp != NULL) {
  847. if (fclose(dfp) == EOF) retval = 0;
  848. }
  849. if (outputs != NULL) FREE(outputs);
  850. if (onames != NULL) FREE(onames);
  851. if (inames != NULL) FREE(inames);
  852. return(retval);
  853. } /* end of Bnet_bddDump */
  854. /**
  855. @brief Writes an array of BDDs to a file in dot, blif, DDcal,
  856. factored-form, daVinci, or blif-MV format.
  857. @details The BDDs and their names are passed as arguments. The
  858. inputs and their names are taken from the network. If "-" is passed
  859. as file name, the BDDs are dumped to the standard output. The encoding
  860. of the format is:
  861. <ul>
  862. <li>0: dot
  863. <li>1: blif
  864. <li>2: da Vinci
  865. <li>3: ddcal
  866. <li>4: factored form
  867. <li>5: blif-MV
  868. </ul>
  869. @return 1 in case of success; 0 otherwise.
  870. @sideeffect None
  871. */
  872. int
  873. Bnet_bddArrayDump(
  874. DdManager * dd /**< %DD manager */,
  875. BnetNetwork * network /**< network whose BDDs should be dumped */,
  876. char * dfile /**< file name */,
  877. DdNode ** outputs /**< BDDs to be dumped */,
  878. char ** onames /**< names of the BDDs to be dumped */,
  879. int noutputs /**< number of BDDs to be dumped */,
  880. int dumpFmt /**< 0 -> dot */)
  881. {
  882. FILE *dfp = NULL;
  883. char **inames = NULL;
  884. BnetNode *node;
  885. int i;
  886. int retval = 0; /* 0 -> failure; 1 -> success */
  887. /* Open dump file. */
  888. if (strcmp(dfile, "-") == 0) {
  889. dfp = stdout;
  890. } else {
  891. dfp = fopen(dfile,"w");
  892. }
  893. if (dfp == NULL) goto endgame;
  894. /* Initialize data structures. */
  895. inames = ALLOC(char *,Cudd_ReadSize(dd));
  896. if (inames == NULL) goto endgame;
  897. for (i = 0; i < Cudd_ReadSize(dd); i++) {
  898. inames[i] = NULL;
  899. }
  900. /* Find the input names. */
  901. for (i = 0; i < network->ninputs; i++) {
  902. if (!st_lookup(network->hash,network->inputs[i],(void **)&node)) {
  903. goto endgame;
  904. }
  905. inames[node->var] = network->inputs[i];
  906. }
  907. for (i = 0; i < network->nlatches; i++) {
  908. if (!st_lookup(network->hash,network->latches[i][1],(void **)&node)) {
  909. goto endgame;
  910. }
  911. inames[node->var] = network->latches[i][1];
  912. }
  913. /* Dump the BDDs. */
  914. if (dumpFmt == 1) {
  915. retval = Cudd_DumpBlif(dd,noutputs,outputs,
  916. (char const * const *) inames,
  917. (char const * const *) onames,
  918. network->name,dfp,0);
  919. } else if (dumpFmt == 2) {
  920. retval = Cudd_DumpDaVinci(dd,noutputs,outputs,
  921. (char const * const *) inames,
  922. (char const * const *) onames,dfp);
  923. } else if (dumpFmt == 3) {
  924. retval = Cudd_DumpDDcal(dd,noutputs,outputs,
  925. (char const * const *) inames,
  926. (char const * const *) onames,dfp);
  927. } else if (dumpFmt == 4) {
  928. retval = Cudd_DumpFactoredForm(dd,noutputs,outputs,
  929. (char const * const *) inames,
  930. (char const * const *) onames,dfp);
  931. } else if (dumpFmt == 5) {
  932. retval = Cudd_DumpBlif(dd,noutputs,outputs,
  933. (char const * const *) inames,
  934. (char const * const *) onames,
  935. network->name,dfp,1);
  936. } else {
  937. retval = Cudd_DumpDot(dd,noutputs,outputs,
  938. (char const * const *) inames,
  939. (char const * const *) onames,dfp);
  940. }
  941. endgame:
  942. if (dfp != stdout && dfp != NULL) {
  943. if (fclose(dfp) == EOF) retval = 0;
  944. }
  945. if (inames != NULL) FREE(inames);
  946. return(retval);
  947. } /* end of Bnet_bddArrayDump */
  948. /**
  949. @brief Reads the variable order from a file.
  950. @return 1 if successful; 0 otherwise.
  951. @sideeffect The BDDs for the primary inputs and present state variables
  952. are built.
  953. */
  954. int
  955. Bnet_ReadOrder(
  956. DdManager * dd,
  957. char * ordFile,
  958. BnetNetwork * net,
  959. int locGlob,
  960. int nodrop)
  961. {
  962. FILE *fp;
  963. st_table *dict;
  964. int result;
  965. BnetNode *node;
  966. char name[MAXLENGTH];
  967. if (ordFile == NULL) {
  968. return(0);
  969. }
  970. dict = st_init_table((st_compare_t) strcmp,st_strhash);
  971. if (dict == NULL) {
  972. return(0);
  973. }
  974. if ((fp = fopen(ordFile,"r")) == NULL) {
  975. (void) fprintf(stderr,"Unable to open %s\n",ordFile);
  976. st_free_table(dict);
  977. return(0);
  978. }
  979. while (!feof(fp)) {
  980. result = fscanf(fp, "%s", name);
  981. if (result == EOF) {
  982. break;
  983. } else if (result != 1) {
  984. st_free_table(dict);
  985. return(0);
  986. } else if (strlen(name) > MAXLENGTH) {
  987. st_free_table(dict);
  988. return(0);
  989. }
  990. /* There should be a node named "name" in the network. */
  991. if (!st_lookup(net->hash,name,(void **)&node)) {
  992. (void) fprintf(stderr,"Unknown name in order file (%s)\n", name);
  993. st_free_table(dict);
  994. return(0);
  995. }
  996. /* A name should not appear more than once in the order. */
  997. if (st_is_member(dict,name)) {
  998. (void) fprintf(stderr,"Duplicate name in order file (%s)\n", name);
  999. st_free_table(dict);
  1000. return(0);
  1001. }
  1002. /* The name should correspond to a primary input or present state. */
  1003. if (node->type != BNET_INPUT_NODE &&
  1004. node->type != BNET_PRESENT_STATE_NODE) {
  1005. (void) fprintf(stderr,"%s has the wrong type (%d)\n", name,
  1006. node->type);
  1007. st_free_table(dict);
  1008. return(0);
  1009. }
  1010. /* Insert in table. Use node->name rather than name, because the
  1011. ** latter gets overwritten.
  1012. */
  1013. if (st_insert(dict,node->name,NULL) == ST_OUT_OF_MEM) {
  1014. (void) fprintf(stderr,"Out of memory in Bnet_ReadOrder\n");
  1015. st_free_table(dict);
  1016. return(0);
  1017. }
  1018. result = Bnet_BuildNodeBDD(dd,node,net->hash,locGlob,nodrop);
  1019. if (result == 0) {
  1020. (void) fprintf(stderr,"Construction of BDD failed\n");
  1021. st_free_table(dict);
  1022. return(0);
  1023. }
  1024. } /* while (!feof(fp)) */
  1025. result = fclose(fp);
  1026. if (result == EOF) {
  1027. (void) fprintf(stderr,"Error closing order file %s\n", ordFile);
  1028. st_free_table(dict);
  1029. return(0);
  1030. }
  1031. /* The number of names in the order file should match exactly the
  1032. ** number of primary inputs and present states.
  1033. */
  1034. if (st_count(dict) != net->ninputs) {
  1035. (void) fprintf(stderr,"Order incomplete: %d names instead of %d\n",
  1036. st_count(dict), net->ninputs);
  1037. st_free_table(dict);
  1038. return(0);
  1039. }
  1040. st_free_table(dict);
  1041. return(1);
  1042. } /* end of Bnet_ReadOrder */
  1043. /**
  1044. @brief Prints the order of the %DD variables of a network.
  1045. @details Only primary inputs and present states are printed.
  1046. @return 1 if successful; 0 otherwise.
  1047. @sideeffect None
  1048. */
  1049. int
  1050. Bnet_PrintOrder(
  1051. BnetNetwork * net,
  1052. DdManager *dd)
  1053. {
  1054. char **names; /* array used to print variable orders */
  1055. int level; /* position of a variable in current order */
  1056. BnetNode *node; /* auxiliary pointer to network node */
  1057. int i,j;
  1058. int retval;
  1059. int nvars;
  1060. nvars = Cudd_ReadSize(dd);
  1061. names = ALLOC(char *, nvars);
  1062. if (names == NULL) return(0);
  1063. for (i = 0; i < nvars; i++) {
  1064. names[i] = NULL;
  1065. }
  1066. for (i = 0; i < net->npis; i++) {
  1067. if (!st_lookup(net->hash,net->inputs[i],(void **)&node)) {
  1068. FREE(names);
  1069. return(0);
  1070. }
  1071. if (node->dd == NULL) {
  1072. FREE(names);
  1073. return(0);
  1074. }
  1075. level = Cudd_ReadPerm(dd,node->var);
  1076. names[level] = node->name;
  1077. }
  1078. for (i = 0; i < net->nlatches; i++) {
  1079. if (!st_lookup(net->hash,net->latches[i][1],(void **)&node)) {
  1080. FREE(names);
  1081. return(0);
  1082. }
  1083. if (node->dd == NULL) {
  1084. FREE(names);
  1085. return(0);
  1086. }
  1087. level = Cudd_ReadPerm(dd,node->var);
  1088. names[level] = node->name;
  1089. }
  1090. for (i = 0, j = 0; i < nvars; i++) {
  1091. if (names[i] == NULL) continue;
  1092. if ((j%8 == 0)&&j) {
  1093. retval = printf("\n");
  1094. if (retval == EOF) {
  1095. FREE(names);
  1096. return(0);
  1097. }
  1098. }
  1099. retval = printf("%s ",names[i]);
  1100. if (retval == EOF) {
  1101. FREE(names);
  1102. return(0);
  1103. }
  1104. j++;
  1105. }
  1106. FREE(names);
  1107. retval = printf("\n");
  1108. if (retval == EOF) {
  1109. return(0);
  1110. }
  1111. return(1);
  1112. } /* end of Bnet_PrintOrder */
  1113. /*---------------------------------------------------------------------------*/
  1114. /* Definition of internal functions */
  1115. /*---------------------------------------------------------------------------*/
  1116. /*---------------------------------------------------------------------------*/
  1117. /* Definition of static functions */
  1118. /*---------------------------------------------------------------------------*/
  1119. /**
  1120. @brief Reads a string from a file.
  1121. @details The string can be MAXLENGTH-1 characters at
  1122. most. readString allocates memory to hold the string.
  1123. @return a pointer to the result string if successful. It returns
  1124. NULL otherwise.
  1125. @sideeffect None
  1126. @see readList
  1127. */
  1128. static char *
  1129. readString(
  1130. FILE * fp /**< pointer to the file from which the string is read */)
  1131. {
  1132. char *savestring;
  1133. int length;
  1134. while (!CurPos) {
  1135. if (!fgets(BuffLine, MAXLENGTH, fp))
  1136. return(NULL);
  1137. BuffLine[strlen(BuffLine) - 1] = '\0';
  1138. CurPos = strtok(BuffLine, " \t");
  1139. if (CurPos && CurPos[0] == '#') CurPos = (char *)NULL;
  1140. }
  1141. length = strlen(CurPos);
  1142. savestring = ALLOC(char,length+1);
  1143. if (savestring == NULL)
  1144. return(NULL);
  1145. strcpy(savestring,CurPos);
  1146. CurPos = strtok(NULL, " \t");
  1147. return(savestring);
  1148. } /* end of readString */
  1149. /**
  1150. @brief Reads a list of strings from a line of a file.
  1151. @details The strings are sequences of characters separated by spaces
  1152. or tabs. The total length of the list, white space included, must
  1153. not exceed MAXLENGTH-1 characters. readList allocates memory for
  1154. the strings and creates an array of pointers to the individual
  1155. lists. Only two pieces of memory are allocated by readList: One to
  1156. hold all the strings, and one to hold the pointers to
  1157. them. Therefore, when freeing the memory allocated by readList, only
  1158. the pointer to the list of pointers, and the pointer to the
  1159. beginning of the first string should be freed.
  1160. @return the pointer to the list of pointers if successful; NULL
  1161. otherwise.
  1162. @sideeffect n is set to the number of strings in the list.
  1163. @see readString printList
  1164. */
  1165. static char **
  1166. readList(
  1167. FILE * fp /**< pointer to the file from which the list is read */,
  1168. int * n /**< on return, number of strings in the list */)
  1169. {
  1170. char *savestring;
  1171. int length;
  1172. char *stack[8192];
  1173. char **list;
  1174. int i, count = 0;
  1175. while (CurPos) {
  1176. if (strcmp(CurPos, "\\") == 0) {
  1177. CurPos = (char *)NULL;
  1178. while (!CurPos) {
  1179. if (!fgets(BuffLine, MAXLENGTH, fp)) return(NULL);
  1180. BuffLine[strlen(BuffLine) - 1] = '\0';
  1181. CurPos = strtok(BuffLine, " \t");
  1182. }
  1183. }
  1184. length = strlen(CurPos);
  1185. savestring = ALLOC(char,length+1);
  1186. if (savestring == NULL) return(NULL);
  1187. strcpy(savestring,CurPos);
  1188. stack[count] = savestring;
  1189. count++;
  1190. CurPos = strtok(NULL, " \t");
  1191. }
  1192. list = ALLOC(char *, count);
  1193. for (i = 0; i < count; i++)
  1194. list[i] = stack[i];
  1195. *n = count;
  1196. return(list);
  1197. } /* end of readList */
  1198. /**
  1199. @brief Prints a list of strings to the standard output.
  1200. @details The list is in the format created by readList.
  1201. @sideeffect None
  1202. @see readList Bnet_PrintNetwork
  1203. */
  1204. static void
  1205. printList(
  1206. char ** list /**< list of pointers to strings */,
  1207. int n /**< length of the list */)
  1208. {
  1209. int i;
  1210. for (i = 0; i < n; i++) {
  1211. (void) fprintf(stdout," %s",list[i]);
  1212. }
  1213. (void) fprintf(stdout,"\n");
  1214. } /* end of printList */
  1215. /**
  1216. @brief Generates n names not currently in a symbol table.
  1217. @details The pointer to the symbol table may be NULL, in which case
  1218. no test is made. The names generated by the procedure are
  1219. unique. So, if there is no possibility of conflict with pre-existing
  1220. names, NULL can be passed for the hash table.
  1221. @return an array of names if succesful; NULL otherwise.
  1222. @sideeffect None
  1223. @see
  1224. */
  1225. static char **
  1226. bnetGenerateNewNames(
  1227. st_table * hash /* table of existing names (or NULL) */,
  1228. int n /* number of names to be generated */)
  1229. {
  1230. char **list;
  1231. char name[256];
  1232. int i;
  1233. if (n < 1) return(NULL);
  1234. list = ALLOC(char *,n);
  1235. if (list == NULL) return(NULL);
  1236. for (i = 0; i < n; i++) {
  1237. do {
  1238. sprintf(name, "var%d", newNameNumber);
  1239. newNameNumber++;
  1240. } while (hash != NULL && st_is_member(hash,name));
  1241. list[i] = util_strsav(name);
  1242. }
  1243. return(list);
  1244. } /* bnetGenerateNewNames */
  1245. /**
  1246. @brief Writes blif for the reencoding logic.
  1247. @sideeffect None
  1248. */
  1249. static int
  1250. bnetDumpReencodingLogic(
  1251. DdManager * dd /**< %DD manager */,
  1252. char * mname /**< model name */,
  1253. int noutputs /**< number of outputs */,
  1254. DdNode ** outputs /**< array of network outputs */,
  1255. char ** inames /**< array of network input names */,
  1256. char ** altnames /**< array of names of reencoded inputs */,
  1257. char ** onames /**< array of network output names */,
  1258. FILE * fp /**< file pointer */)
  1259. {
  1260. int i;
  1261. int retval;
  1262. int nvars = Cudd_ReadSize(dd);
  1263. int *support = NULL;
  1264. support = bnetFindVectorSupport(dd,outputs,noutputs);
  1265. if (support == NULL) return(0);
  1266. /* Write the header (.model .inputs .outputs). */
  1267. retval = fprintf(fp,".model %s.global\n.inputs",mname);
  1268. if (retval == EOF) goto failure;
  1269. for (i = 0; i < nvars; i++) {
  1270. if ((i%8 == 0)&&i) {
  1271. retval = fprintf(fp," \\\n");
  1272. if (retval == EOF) goto failure;
  1273. }
  1274. retval = fprintf(fp," %s", inames[i]);
  1275. if (retval == EOF) goto failure;
  1276. }
  1277. /* Write the .output line. */
  1278. retval = fprintf(fp,"\n.outputs");
  1279. if (retval == EOF) goto failure;
  1280. for (i = 0; i < noutputs; i++) {
  1281. if ((i%8 == 0)&&i) {
  1282. retval = fprintf(fp," \\\n");
  1283. if (retval == EOF) goto failure;
  1284. }
  1285. retval = fprintf(fp," %s", onames[i]);
  1286. if (retval == EOF) goto failure;
  1287. }
  1288. retval = fprintf(fp,"\n");
  1289. if (retval == EOF) goto failure;
  1290. /* Instantiate main subcircuit. */
  1291. retval = fprintf(fp,"\n.subckt %s", mname);
  1292. if (retval == EOF) goto failure;
  1293. for (i = 0; i < nvars; i++) {
  1294. if ((i%8 == 0)&&i) {
  1295. retval = fprintf(fp," \\\n");
  1296. if (retval == EOF) goto failure;
  1297. }
  1298. if (support[i] == 1) {
  1299. retval = fprintf(fp," %s=%s", inames[i], altnames[i]);
  1300. if (retval == EOF) goto failure;
  1301. }
  1302. }
  1303. for (i = 0; i < noutputs; i++) {
  1304. if ((i%8 == 0)&&i) {
  1305. retval = fprintf(fp," \\\n");
  1306. if (retval == EOF) goto failure;
  1307. }
  1308. retval = fprintf(fp," %s=%s", onames[i], onames[i]);
  1309. if (retval == EOF) goto failure;
  1310. }
  1311. retval = fprintf(fp,"\n");
  1312. if (retval == EOF) goto failure;
  1313. /* Instantiate reencoding subcircuit. */
  1314. retval = fprintf(fp,"\n.subckt %s.reencode",mname);
  1315. if (retval == EOF) goto failure;
  1316. for (i = 0; i < nvars; i++) {
  1317. if ((i%8 == 0)&&i) {
  1318. retval = fprintf(fp," \\\n");
  1319. if (retval == EOF) goto failure;
  1320. }
  1321. retval = fprintf(fp," %s=%s", inames[i], inames[i]);
  1322. if (retval == EOF) goto failure;
  1323. }
  1324. retval = fprintf(fp," \\\n");
  1325. if (retval == EOF) goto failure;
  1326. for (i = 0; i < nvars; i++) {
  1327. if ((i%8 == 0)&&i) {
  1328. retval = fprintf(fp," \\\n");
  1329. if (retval == EOF) goto failure;
  1330. }
  1331. if (support[i] == 1) {
  1332. retval = fprintf(fp," %s=%s", altnames[i],altnames[i]);
  1333. if (retval == EOF) goto failure;
  1334. }
  1335. }
  1336. retval = fprintf(fp,"\n");
  1337. if (retval == EOF) goto failure;
  1338. /* Write trailer. */
  1339. retval = fprintf(fp,".end\n\n");
  1340. if (retval == EOF) goto failure;
  1341. /* Write reencoding subcircuit. */
  1342. retval = bnetBlifWriteReencode(dd,mname,inames,altnames,support,fp);
  1343. if (retval == EOF) goto failure;
  1344. FREE(support);
  1345. return(1);
  1346. failure:
  1347. if (support != NULL) FREE(support);
  1348. return(0);
  1349. } /* end of bnetDumpReencodingLogic */
  1350. /**
  1351. @brief Writes blif for the truth table of an n-input xnor.
  1352. @return 1 if successful; 0 otherwise.
  1353. @sideeffect None
  1354. */
  1355. #if 0
  1356. static int
  1357. bnetBlifXnorTable(
  1358. FILE * fp /**< file pointer */,
  1359. int n /**< number of inputs */)
  1360. {
  1361. int power; /* 2 to the power n */
  1362. int i,j,k;
  1363. int nzeroes;
  1364. int retval;
  1365. char *line;
  1366. line = ALLOC(char,n+1);
  1367. if (line == NULL) return(0);
  1368. line[n] = '\0';
  1369. for (i = 0, power = 1; i < n; i++) {
  1370. power *= 2;
  1371. }
  1372. for (i = 0; i < power; i++) {
  1373. k = i;
  1374. nzeroes = 0;
  1375. for (j = 0; j < n; j++) {
  1376. if (k & 1) {
  1377. line[j] = '1';
  1378. } else {
  1379. line[j] = '0';
  1380. nzeroes++;
  1381. }
  1382. k >>= 1;
  1383. }
  1384. if ((nzeroes & 1) == 0) {
  1385. retval = fprintf(fp,"%s 1\n",line);
  1386. if (retval == 0) return(0);
  1387. }
  1388. }
  1389. return(1);
  1390. } /* end of bnetBlifXnorTable */
  1391. #endif
  1392. /**
  1393. @brief Writes blif for the reencoding logic.
  1394. @details Exclusive NORs with more than two inputs are decomposed
  1395. into cascaded two-input gates.
  1396. @return 1 if successful; 0 otherwise.
  1397. @sideeffect None
  1398. */
  1399. static int
  1400. bnetBlifWriteReencode(
  1401. DdManager * dd,
  1402. char * mname,
  1403. char ** inames,
  1404. char ** altnames,
  1405. int * support,
  1406. FILE * fp)
  1407. {
  1408. int retval;
  1409. int nvars = Cudd_ReadSize(dd);
  1410. int i,j;
  1411. int ninp;
  1412. /* Write the header (.model .inputs .outputs). */
  1413. retval = fprintf(fp,".model %s.reencode\n.inputs",mname);
  1414. if (retval == EOF) return(0);
  1415. for (i = 0; i < nvars; i++) {
  1416. if ((i%8 == 0)&&i) {
  1417. retval = fprintf(fp," \\\n");
  1418. if (retval == EOF) goto failure;
  1419. }
  1420. retval = fprintf(fp," %s", inames[i]);
  1421. if (retval == EOF) goto failure;
  1422. }
  1423. /* Write the .output line. */
  1424. retval = fprintf(fp,"\n.outputs");
  1425. if (retval == EOF) goto failure;
  1426. for (i = 0; i < nvars; i++) {
  1427. if ((i%8 == 0)&&i) {
  1428. retval = fprintf(fp," \\\n");
  1429. if (retval == EOF) goto failure;
  1430. }
  1431. if (support[i] == 1) {
  1432. retval = fprintf(fp," %s", altnames[i]);
  1433. if (retval == EOF) goto failure;
  1434. }
  1435. }
  1436. retval = fprintf(fp,"\n");
  1437. if (retval == EOF) goto failure;
  1438. /* Instantiate exclusive nors. */
  1439. for (i = 0; i < nvars; i++) {
  1440. char *in1 = NULL;
  1441. char *in2 = NULL;
  1442. char **oname;
  1443. if (support[i] == 0) continue;
  1444. ninp = 0;
  1445. for (j = 0; j < nvars; j++) {
  1446. if (Cudd_ReadLinear(dd,i,j)) {
  1447. switch (ninp) {
  1448. case 0:
  1449. in1 = inames[j];
  1450. ninp++;
  1451. break;
  1452. case 1:
  1453. in2 = inames[j];
  1454. ninp++;
  1455. break;
  1456. case 2:
  1457. oname = bnetGenerateNewNames(NULL,1);
  1458. retval = fprintf(fp,".names %s %s %s\n11 1\n00 1\n",
  1459. in1, in2, oname[0]);
  1460. if (retval == EOF) goto failure;
  1461. in1 = oname[0];
  1462. in2 = inames[j];
  1463. FREE(oname);
  1464. break;
  1465. default:
  1466. goto failure;
  1467. }
  1468. }
  1469. }
  1470. switch (ninp) {
  1471. case 1:
  1472. retval = fprintf(fp,".names %s %s\n1 1\n", in1, altnames[i]);
  1473. if (retval == EOF) goto failure;
  1474. break;
  1475. case 2:
  1476. retval = fprintf(fp,".names %s %s %s\n11 1\n00 1\n",
  1477. in1, in2, altnames[i]);
  1478. if (retval == EOF) goto failure;
  1479. break;
  1480. default:
  1481. goto failure;
  1482. }
  1483. }
  1484. /* Write trailer. */
  1485. retval = fprintf(fp,"\n.end\n\n");
  1486. if (retval == EOF) goto failure;
  1487. return(1);
  1488. failure:
  1489. return(0);
  1490. } /* end of bnetBlifWriteReencode */
  1491. /**
  1492. @brief Finds the support of a list of DDs.
  1493. @sideeffect None
  1494. */
  1495. static int *
  1496. bnetFindVectorSupport(
  1497. DdManager * dd,
  1498. DdNode ** list,
  1499. int n)
  1500. {
  1501. DdNode *support = NULL;
  1502. DdNode *scan;
  1503. int *array = NULL;
  1504. int nvars = Cudd_ReadSize(dd);
  1505. int i;
  1506. /* Build an array with the support of the functions in list. */
  1507. array = ALLOC(int,nvars);
  1508. if (array == NULL) return(NULL);
  1509. for (i = 0; i < nvars; i++) {
  1510. array[i] = 0;
  1511. }
  1512. /* Take the union of the supports of each output function. */
  1513. for (i = 0; i < n; i++) {
  1514. support = Cudd_Support(dd,list[i]);
  1515. if (support == NULL) {
  1516. FREE(array);
  1517. return(NULL);
  1518. }
  1519. Cudd_Ref(support);
  1520. scan = support;
  1521. while (!Cudd_IsConstant(scan)) {
  1522. array[scan->index] = 1;
  1523. scan = Cudd_T(scan);
  1524. }
  1525. Cudd_IterDerefBdd(dd,support);
  1526. }
  1527. return(array);
  1528. } /* end of bnetFindVectorSupport */
  1529. /**
  1530. @brief Builds %BDD for a XOR function.
  1531. @details Checks whether a function is a XOR with 2 or 3 inputs. If so,
  1532. it builds the %BDD.
  1533. @return 1 if the %BDD has been built; 0 otherwise.
  1534. @sideeffect None
  1535. */
  1536. static int
  1537. buildExorBDD(
  1538. DdManager * dd,
  1539. BnetNode * nd,
  1540. st_table * hash,
  1541. int params,
  1542. int nodrop)
  1543. {
  1544. int check[8];
  1545. int i;
  1546. int nlines;
  1547. BnetTabline *line;
  1548. DdNode *func, *var, *tmp;
  1549. BnetNode *auxnd;
  1550. if (nd->ninp < 2 || nd->ninp > 3) return(0);
  1551. nlines = 1 << (nd->ninp - 1);
  1552. for (i = 0; i < 8; i++) check[i] = 0;
  1553. line = nd->f;
  1554. while (line != NULL) {
  1555. int num = 0;
  1556. int count = 0;
  1557. nlines--;
  1558. for (i = 0; i < nd->ninp; i++) {
  1559. num <<= 1;
  1560. if (line->values[i] == '-') {
  1561. return(0);
  1562. } else if (line->values[i] == '1') {
  1563. count++;
  1564. num++;
  1565. }
  1566. }
  1567. if ((count & 1) == 0) return(0);
  1568. if (check[num]) return(0);
  1569. line = line->next;
  1570. }
  1571. if (nlines != 0) return(0);
  1572. /* Initialize the exclusive sum to logical 0. */
  1573. func = Cudd_ReadLogicZero(dd);
  1574. Cudd_Ref(func);
  1575. /* Scan the inputs. */
  1576. for (i = 0; i < nd->ninp; i++) {
  1577. if (!st_lookup(hash, nd->inputs[i], (void **) &auxnd)) {
  1578. goto failure;
  1579. }
  1580. if (params == BNET_LOCAL_DD) {
  1581. if (auxnd->active == FALSE) {
  1582. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1583. goto failure;
  1584. }
  1585. }
  1586. var = Cudd_ReadVars(dd,auxnd->var);
  1587. if (var == NULL) goto failure;
  1588. Cudd_Ref(var);
  1589. } else { /* params == BNET_GLOBAL_DD */
  1590. if (auxnd->dd == NULL) {
  1591. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1592. goto failure;
  1593. }
  1594. }
  1595. var = auxnd->dd;
  1596. }
  1597. tmp = Cudd_bddXor(dd,func,var);
  1598. if (tmp == NULL) goto failure;
  1599. Cudd_Ref(tmp);
  1600. Cudd_IterDerefBdd(dd,func);
  1601. if (params == BNET_LOCAL_DD) {
  1602. Cudd_IterDerefBdd(dd,var);
  1603. }
  1604. func = tmp;
  1605. }
  1606. nd->dd = func;
  1607. /* Associate a variable to this node if local BDDs are being
  1608. ** built. This is done at the end, so that the primary inputs tend
  1609. ** to get lower indices.
  1610. */
  1611. if (params == BNET_LOCAL_DD && nd->active == FALSE) {
  1612. DdNode *auxfunc = Cudd_bddNewVar(dd);
  1613. if (auxfunc == NULL) goto failure;
  1614. Cudd_Ref(auxfunc);
  1615. nd->var = auxfunc->index;
  1616. nd->active = TRUE;
  1617. Cudd_IterDerefBdd(dd,auxfunc);
  1618. }
  1619. return(1);
  1620. failure:
  1621. return(0);
  1622. } /* end of buildExorBDD */
  1623. /**
  1624. @brief Builds %BDD for a multiplexer.
  1625. @details Checks whether a function is a 2-to-1 multiplexer. If so,
  1626. it builds the %BDD.
  1627. @return 1 if the %BDD has been built; 0 otherwise.
  1628. @sideeffect None
  1629. */
  1630. static int
  1631. buildMuxBDD(
  1632. DdManager * dd,
  1633. BnetNode * nd,
  1634. st_table * hash,
  1635. int params,
  1636. int nodrop)
  1637. {
  1638. BnetTabline *line;
  1639. char *values[2];
  1640. int mux[2] = {0, 0};
  1641. int phase[2] = {0, 0};
  1642. int j;
  1643. int nlines = 0;
  1644. int controlC = -1;
  1645. int controlR = -1;
  1646. DdNode *func, *f, *g, *h;
  1647. BnetNode *auxnd;
  1648. if (nd->ninp != 3 || nd->f == NULL) return(0);
  1649. for (line = nd->f; line != NULL; line = line->next) {
  1650. int dc = 0;
  1651. if (nlines > 1) return(0);
  1652. values[nlines] = line->values;
  1653. for (j = 0; j < 3; j++) {
  1654. if (values[nlines][j] == '-') {
  1655. if (dc) return(0);
  1656. dc = 1;
  1657. }
  1658. }
  1659. if (!dc) return(0);
  1660. nlines++;
  1661. }
  1662. if (nlines != 2) return(0);
  1663. /* At this point we know we have:
  1664. ** 3 inputs
  1665. ** 2 lines
  1666. ** 1 dash in each line
  1667. ** If the two dashes are not in the same column, then there is
  1668. ** exaclty one column without dashes: the control column.
  1669. */
  1670. for (j = 0; j < 3; j++) {
  1671. if (values[0][j] == '-' && values[1][j] == '-') return(0);
  1672. if (values[0][j] != '-' && values[1][j] != '-') {
  1673. if (values[0][j] == values[1][j]) return(0);
  1674. controlC = j;
  1675. controlR = values[0][j] == '0';
  1676. }
  1677. }
  1678. assert(controlC != -1 && controlR != -1);
  1679. /* At this point we know that there is indeed no column with two
  1680. ** dashes. The control column has been identified, and we know that
  1681. ** its two elelments are different. */
  1682. for (j = 0; j < 3; j++) {
  1683. if (j == controlC) continue;
  1684. if (values[controlR][j] == '1') {
  1685. mux[0] = j;
  1686. phase[0] = 0;
  1687. } else if (values[controlR][j] == '0') {
  1688. mux[0] = j;
  1689. phase[0] = 1;
  1690. } else if (values[1-controlR][j] == '1') {
  1691. mux[1] = j;
  1692. phase[1] = 0;
  1693. } else if (values[1-controlR][j] == '0') {
  1694. mux[1] = j;
  1695. phase[1] = 1;
  1696. }
  1697. }
  1698. /* Get the inputs. */
  1699. if (!st_lookup(hash, nd->inputs[controlC], (void **) &auxnd)) {
  1700. goto failure;
  1701. }
  1702. if (params == BNET_LOCAL_DD) {
  1703. if (auxnd->active == FALSE) {
  1704. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1705. goto failure;
  1706. }
  1707. }
  1708. f = Cudd_ReadVars(dd,auxnd->var);
  1709. if (f == NULL) goto failure;
  1710. Cudd_Ref(f);
  1711. } else { /* params == BNET_GLOBAL_DD */
  1712. if (auxnd->dd == NULL) {
  1713. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1714. goto failure;
  1715. }
  1716. }
  1717. f = auxnd->dd;
  1718. }
  1719. if (!st_lookup(hash, nd->inputs[mux[0]], (void **) &auxnd)) {
  1720. goto failure;
  1721. }
  1722. if (params == BNET_LOCAL_DD) {
  1723. if (auxnd->active == FALSE) {
  1724. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1725. goto failure;
  1726. }
  1727. }
  1728. g = Cudd_ReadVars(dd,auxnd->var);
  1729. if (g == NULL) goto failure;
  1730. Cudd_Ref(g);
  1731. } else { /* params == BNET_GLOBAL_DD */
  1732. if (auxnd->dd == NULL) {
  1733. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1734. goto failure;
  1735. }
  1736. }
  1737. g = auxnd->dd;
  1738. }
  1739. g = Cudd_NotCond(g,phase[0]);
  1740. if (!st_lookup(hash, nd->inputs[mux[1]], (void **) &auxnd)) {
  1741. goto failure;
  1742. }
  1743. if (params == BNET_LOCAL_DD) {
  1744. if (auxnd->active == FALSE) {
  1745. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1746. goto failure;
  1747. }
  1748. }
  1749. h = Cudd_ReadVars(dd,auxnd->var);
  1750. if (h == NULL) goto failure;
  1751. Cudd_Ref(h);
  1752. } else { /* params == BNET_GLOBAL_DD */
  1753. if (auxnd->dd == NULL) {
  1754. if (!Bnet_BuildNodeBDD(dd,auxnd,hash,params,nodrop)) {
  1755. goto failure;
  1756. }
  1757. }
  1758. h = auxnd->dd;
  1759. }
  1760. h = Cudd_NotCond(h,phase[1]);
  1761. func = Cudd_bddIte(dd,f,g,h);
  1762. if (func == NULL) goto failure;
  1763. Cudd_Ref(func);
  1764. if (params == BNET_LOCAL_DD) {
  1765. Cudd_IterDerefBdd(dd,f);
  1766. Cudd_IterDerefBdd(dd,g);
  1767. Cudd_IterDerefBdd(dd,h);
  1768. }
  1769. nd->dd = func;
  1770. /* Associate a variable to this node if local BDDs are being
  1771. ** built. This is done at the end, so that the primary inputs tend
  1772. ** to get lower indices.
  1773. */
  1774. if (params == BNET_LOCAL_DD && nd->active == FALSE) {
  1775. DdNode *auxfunc = Cudd_bddNewVar(dd);
  1776. if (auxfunc == NULL) goto failure;
  1777. Cudd_Ref(auxfunc);
  1778. nd->var = auxfunc->index;
  1779. nd->active = TRUE;
  1780. Cudd_IterDerefBdd(dd,auxfunc);
  1781. }
  1782. return(1);
  1783. failure:
  1784. return(0);
  1785. } /* end of buildExorBDD */
  1786. /**
  1787. @brief Sets the level of each node.
  1788. @return 1 if successful; 0 otherwise.
  1789. @sideeffect Changes the level and visited fields of the nodes it
  1790. visits.
  1791. @see bnetLevelDFS
  1792. */
  1793. static int
  1794. bnetSetLevel(
  1795. BnetNetwork * net)
  1796. {
  1797. BnetNode *node;
  1798. /* Recursively visit nodes. This is pretty inefficient, because we
  1799. ** visit all nodes in this loop, and most of them in the recursive
  1800. ** calls to bnetLevelDFS. However, this approach guarantees that
  1801. ** all nodes will be reached ven if there are dangling outputs. */
  1802. node = net->nodes;
  1803. while (node != NULL) {
  1804. if (!bnetLevelDFS(net,node)) return(0);
  1805. node = node->next;
  1806. }
  1807. /* Clear visited flags. */
  1808. node = net->nodes;
  1809. while (node != NULL) {
  1810. node->visited = 0;
  1811. node = node->next;
  1812. }
  1813. return(1);
  1814. } /* end of bnetSetLevel */
  1815. /**
  1816. @brief Does a DFS from a node setting the level field.
  1817. @return 1 if successful; 0 otherwise.
  1818. @sideeffect Changes the level and visited fields of the nodes it
  1819. visits.
  1820. @see bnetSetLevel
  1821. */
  1822. static int
  1823. bnetLevelDFS(
  1824. BnetNetwork * net,
  1825. BnetNode * node)
  1826. {
  1827. int i;
  1828. BnetNode *auxnd;
  1829. if (node->visited == 1) {
  1830. return(1);
  1831. }
  1832. node->visited = 1;
  1833. /* Graphical sources have level 0. This is the final value if the
  1834. ** node has no fan-ins. Otherwise the successive loop will
  1835. ** increase the level. */
  1836. node->level = 0;
  1837. for (i = 0; i < node->ninp; i++) {
  1838. if (!st_lookup(net->hash, node->inputs[i], (void **) &auxnd)) {
  1839. return(0);
  1840. }
  1841. if (!bnetLevelDFS(net,auxnd)) {
  1842. return(0);
  1843. }
  1844. if (auxnd->level >= node->level) node->level = 1 + auxnd->level;
  1845. }
  1846. return(1);
  1847. } /* end of bnetLevelDFS */
  1848. /**
  1849. @brief Orders network roots for variable ordering.
  1850. @return an array with the ordered outputs and next state variables
  1851. if successful; NULL otherwise.
  1852. @sideeffect None
  1853. */
  1854. static BnetNode **
  1855. bnetOrderRoots(
  1856. BnetNetwork * net,
  1857. int * nroots)
  1858. {
  1859. int i, noutputs;
  1860. BnetNode *node;
  1861. BnetNode **nodes = NULL;
  1862. /* Initialize data structures. */
  1863. noutputs = net->noutputs;
  1864. nodes = ALLOC(BnetNode *, noutputs);
  1865. if (nodes == NULL) goto endgame;
  1866. /* Find output names and levels. */
  1867. for (i = 0; i < net->noutputs; i++) {
  1868. if (!st_lookup(net->hash,net->outputs[i],(void **)&node)) {
  1869. goto endgame;
  1870. }
  1871. nodes[i] = node;
  1872. }
  1873. util_qsort(nodes, noutputs, sizeof(BnetNode *),
  1874. (DD_QSFP)bnetLevelCompare);
  1875. *nroots = noutputs;
  1876. return(nodes);
  1877. endgame:
  1878. if (nodes != NULL) FREE(nodes);
  1879. return(NULL);
  1880. } /* end of bnetOrderRoots */
  1881. /**
  1882. @brief Comparison function used by qsort.
  1883. @details Used to order the variables according to the number of keys
  1884. in the subtables.
  1885. @return the difference in number of keys between the two variables
  1886. being compared.
  1887. @sideeffect None
  1888. */
  1889. static int
  1890. bnetLevelCompare(
  1891. BnetNode ** x,
  1892. BnetNode ** y)
  1893. {
  1894. return((*y)->level - (*x)->level);
  1895. } /* end of bnetLevelCompare */
  1896. /**
  1897. @brief Does a DFS from a node ordering the inputs.
  1898. @return 1 if successful; 0 otherwise.
  1899. @sideeffect Changes visited fields of the nodes it visits.
  1900. @see Bnet_DfsVariableOrder
  1901. */
  1902. static int
  1903. bnetDfsOrder(
  1904. DdManager * dd,
  1905. BnetNetwork * net,
  1906. BnetNode * node)
  1907. {
  1908. int i;
  1909. BnetNode *auxnd;
  1910. BnetNode **fanins;
  1911. if (node->visited == 1) {
  1912. return(1);
  1913. }
  1914. node->visited = 1;
  1915. if (node->type == BNET_INPUT_NODE ||
  1916. node->type == BNET_PRESENT_STATE_NODE) {
  1917. node->dd = Cudd_bddNewVar(dd);
  1918. if (node->dd == NULL) return(0);
  1919. Cudd_Ref(node->dd);
  1920. node->active = TRUE;
  1921. node->var = node->dd->index;
  1922. return(1);
  1923. }
  1924. fanins = ALLOC(BnetNode *, node->ninp);
  1925. if (fanins == NULL) return(0);
  1926. for (i = 0; i < node->ninp; i++) {
  1927. if (!st_lookup(net->hash, node->inputs[i], (void **) &auxnd)) {
  1928. FREE(fanins);
  1929. return(0);
  1930. }
  1931. fanins[i] = auxnd;
  1932. }
  1933. util_qsort(fanins, node->ninp, sizeof(BnetNode *),
  1934. (DD_QSFP)bnetLevelCompare);
  1935. for (i = 0; i < node->ninp; i++) {
  1936. /* for (i = node->ninp - 1; i >= 0; i--) { */
  1937. int res = bnetDfsOrder(dd,net,fanins[i]);
  1938. if (res == 0) {
  1939. FREE(fanins);
  1940. return(0);
  1941. }
  1942. }
  1943. FREE(fanins);
  1944. return(1);
  1945. } /* end of bnetLevelDFS */