VIS

src/eqv/eqvVerify.c

Go to the documentation of this file.
00001 
00037 #include "eqvInt.h"
00038 
00039 static char rcsid[] UNUSED = "$Id: eqvVerify.c,v 1.10 2009/04/11 01:40:06 fabio Exp $";
00040 
00043 /*---------------------------------------------------------------------------*/
00044 /* Static function prototypes                                                */
00045 /*---------------------------------------------------------------------------*/
00046 
00047 
00051 /*---------------------------------------------------------------------------*/
00052 /* Definition of exported functions                                          */
00053 /*---------------------------------------------------------------------------*/
00054 
00082 boolean
00083 Eqv_NetworkVerifyCombinationalEquivalence(
00084   Ntk_Network_t *network1,
00085   Ntk_Network_t *network2,
00086   st_table *leavesMap,  /* the mapping between the inputs of the networks;
00087                          * hash table from Ntk_Node_t * to Ntk_Node_t * */
00088   st_table *rootsMap,   /* the mapping between the outputs of the networks;
00089                          * hash table from Ntk_Node_t * to Ntk_Node_t * */
00090   OFT AssignCommonOrder,
00091   Part_PartitionMethod method1,
00092   Part_PartitionMethod method2)
00093 {
00094   mdd_manager *mddMgr;
00095   lsList leavesList1, leavesList2;
00096   lsList rootsList1, rootsList2;
00097   st_table *leaves1, *leaves2;
00098   array_t *roots1, *roots2;
00099   st_generator *gen;
00100   lsGen listGen;
00101   graph_t *rootsToLeaves1, *rootsToLeaves2;
00102   Ntk_Node_t *node1, *node2;
00103   char *name1, *name2, *name;
00104   Mvf_Function_t *func1, *func2;
00105   int num, i, j;
00106   array_t *mvfRoots1, *mvfRoots2;
00107   boolean equivalent = TRUE;
00108   lsList dummy = (lsList) 0;
00109   int mddId1, mddId2;
00110   vertex_t *vertex;
00111   lsGeneric data;
00112   boolean partValid = FALSE;
00113   mdd_manager *mgr;
00114   int mddId;
00115   array_t *mddIdArray;
00116   mdd_t *aMinterm, *diff;
00117   char *mintermName;
00118   mdd_t *comp1, *comp2;
00119   int numComponents;
00120 
00121   /* First check whether a partition is registered with network1 */
00122   if(Ntk_NetworkReadApplInfo(network1, PART_NETWORK_APPL_KEY) != NIL(void)) {
00123     /*
00124      * Check whether the registered partition can be used to compute the roots
00125      * in terms of the leaves. If it can be used, then i won't create a new
00126      * one.
00127      */
00128     partValid = TestPartitionIsValid(network1, rootsMap, leavesMap);
00129     /*
00130      * If a partition already exists, an mddManager also exists.
00131      * So, don't allocate a new one.
00132      */
00133     mddMgr = Ntk_NetworkReadMddManager(network1);
00134   }
00135   else {
00136     mddMgr = Ntk_NetworkInitializeMddManager(network1);
00137   }
00138   assert(mddMgr != NIL(mdd_manager));
00139   Ntk_NetworkSetMddManager(network2, mddMgr);
00140   (*AssignCommonOrder)(network1, network2, leavesMap);
00141 
00142   /* Create lists of leaves and roots for creating partitions. */
00143   leavesList1 = lsCreate();
00144   leavesList2 = lsCreate();
00145   st_foreach_item(leavesMap, gen, &node1, &node2) {
00146     mddId1 = Ntk_NodeReadMddId(node1);
00147     mddId2 = Ntk_NodeReadMddId(node2);
00148     assert(mddId1 == mddId2);
00149     lsNewEnd(leavesList1, (lsGeneric) node1, LS_NH);
00150     lsNewEnd(leavesList2, (lsGeneric) node2, LS_NH);
00151   }
00152 
00153   rootsList1 = lsCreate();
00154   rootsList2 = lsCreate();
00155   st_foreach_item(rootsMap, gen, &node1, &node2) {
00156     lsNewEnd(rootsList1, (lsGeneric) node1, LS_NH);
00157     lsNewEnd(rootsList2, (lsGeneric) node2, LS_NH);
00158   }
00159 
00160   if(partValid) {
00161     rootsToLeaves1 = Part_NetworkReadPartition(network1);
00162   }
00163   else {
00164     rootsToLeaves1 = Part_NetworkCreatePartition(network1, NIL(Hrc_Node_t),
00165                                                  "dummy", rootsList1,
00166                                                  leavesList1, NIL(mdd_t),
00167                                                  method1, dummy,
00168                                                  FALSE, FALSE, TRUE);
00169   }
00170 
00171   /*
00172    * Generate arrays of root and leaf vertices in the first partition
00173    * to pass as arguments to Part_PartitionCollapse().
00174    */
00175   roots1 = array_alloc(vertex_t *, 0);
00176   lsForEachItem(rootsList1, listGen, data) {
00177     name = Ntk_NodeReadName((Ntk_Node_t *) data);
00178     vertex = Part_PartitionFindVertexByName(rootsToLeaves1, name);
00179     assert(vertex != NIL(vertex_t));
00180     array_insert_last(vertex_t *, roots1, vertex);
00181   }
00182   leaves1 = st_init_table(st_ptrcmp, st_ptrhash);
00183   lsForEachItem(leavesList1, listGen, data) {
00184     name = Ntk_NodeReadName((Ntk_Node_t *) data);
00185     vertex = Part_PartitionFindVertexByName(rootsToLeaves1, name);
00186 /*    assert(vertex != NIL(vertex_t)); */
00187     if(vertex != NIL(vertex_t)) {
00188       /*
00189        * If a leaf is not actually in the support of the roots then
00190        * it will not be present in the partition.
00191        */
00192       mddId = Part_VertexReadMddId(vertex);
00193       st_insert(leaves1, (char *) vertex, (char *) (long) mddId);
00194     }
00195   }
00196 
00197   lsDestroy(rootsList1, (void (*) (lsGeneric)) 0);
00198   lsDestroy(leavesList1, (void (*) (lsGeneric)) 0);
00199   rootsToLeaves2 = Part_NetworkCreatePartition(network2, NIL(Hrc_Node_t),
00200                                                "dummy", rootsList2,
00201                                                leavesList2, NIL(mdd_t),
00202                                                method2, dummy, FALSE,
00203                                                FALSE, TRUE);
00204 
00205   /*
00206    * Generate arrays of root and leaf vertices in the second partition
00207    * to pass as arguments to Part_PartitionCollapse().
00208    */
00209   roots2 = array_alloc(vertex_t *, 0);
00210   lsForEachItem(rootsList2, listGen, data) {
00211     name = Ntk_NodeReadName((Ntk_Node_t *) data);
00212     vertex = Part_PartitionFindVertexByName(rootsToLeaves2, name);
00213     assert(vertex != NIL(vertex_t));
00214     array_insert_last(vertex_t *, roots2, vertex);
00215   }
00216   leaves2 = st_init_table(st_ptrcmp, st_ptrhash);
00217   lsForEachItem(leavesList2, listGen, data) {
00218     name = Ntk_NodeReadName((Ntk_Node_t *) data);
00219     vertex = Part_PartitionFindVertexByName(rootsToLeaves2, name);
00220 /*    assert(vertex != NIL(vertex_t)); */
00221     if(vertex != NIL(vertex_t)) {
00222       /*
00223        * If a leaf is not actually in the support of the roots then
00224        * it will not be present in the partition.
00225        */
00226       mddId = Part_VertexReadMddId(vertex);
00227       st_insert(leaves2, (char *) vertex, (char *) (long) mddId);
00228     }
00229   }
00230   lsDestroy(rootsList2, (void (*) (lsGeneric)) 0);
00231   lsDestroy(leavesList2, (void (*) (lsGeneric)) 0);
00232   assert(Part_PartitionReadMddManager(rootsToLeaves1) ==
00233          Part_PartitionReadMddManager(rootsToLeaves2));
00234 
00235   mvfRoots1 = Part_PartitionCollapse(rootsToLeaves1, roots1, leaves1, NIL(mdd_t));
00236   mvfRoots2 = Part_PartitionCollapse(rootsToLeaves2, roots2, leaves2, NIL(mdd_t));
00237 
00238   assert(array_n(mvfRoots1) == array_n(mvfRoots2));
00239   num = array_n(mvfRoots1);
00240   mddIdArray = array_alloc(int, 0);
00241   st_foreach_item_int(leaves1, gen, &vertex, &mddId) {
00242     array_insert_last(int, mddIdArray, mddId);
00243   }
00244 
00245   /*
00246    * For each pair of corresponding outputs in the two arrays mvfRoots1 and
00247    * mvfRoots2, I will compute the mdd representing all the input combinations
00248    * for which they are different. For each pair, I will print one input
00249    * combination for which they are different.
00250    */
00251 
00252   for(i = 0; i<num; ++i) {
00253     func1 = array_fetch(Mvf_Function_t *, mvfRoots1, i);
00254     func2 = array_fetch(Mvf_Function_t *, mvfRoots2, i);
00255     if(!Mvf_FunctionTestIsEqualToFunction(func1, func2)) {
00256       mgr = Mvf_FunctionReadMddManager(func1);
00257       assert(mgr == Mvf_FunctionReadMddManager(func2));
00258       numComponents = Mvf_FunctionReadNumComponents(func1);
00259       for(j=0; j<numComponents; ++j) {
00260         comp1 = Mvf_FunctionReadComponent(func1, j);
00261         comp2 = Mvf_FunctionReadComponent(func2, j);
00262         diff = mdd_xor(comp1, comp2);
00263         if(!mdd_is_tautology(diff, 0)) {
00264           aMinterm = Mc_ComputeAMinterm(diff, mddIdArray, mddMgr);
00265           mintermName = Mc_MintermToString(aMinterm, mddIdArray, network1);
00266           vertex = array_fetch(vertex_t *, roots1, i);
00267           name1 = Part_VertexReadName(vertex);
00268           vertex = array_fetch(vertex_t *, roots2, i);
00269           name2 = Part_VertexReadName(vertex);
00270           (void) fprintf(vis_stdout, "%s from network1 and %s from network2 differ on input values\n%s",
00271                          name1, name2, mintermName);
00272           FREE(mintermName);
00273           mdd_free(aMinterm);
00274           mdd_free(diff);
00275           break;
00276         }
00277         mdd_free(diff);
00278       }
00279       equivalent = FALSE;
00280     }
00281   }
00282   array_free(mddIdArray);
00283   if(!partValid) {
00284     Part_PartitionFree(rootsToLeaves1);
00285   }
00286   Part_PartitionFree(rootsToLeaves2);
00287   array_free(roots1);
00288   array_free(roots2);
00289   st_free_table(leaves1);
00290   st_free_table(leaves2);
00291   arrayForEachItem(Mvf_Function_t *, mvfRoots1, i, func1) {
00292     Mvf_FunctionFree(func1);
00293   }
00294   array_free(mvfRoots1);
00295   arrayForEachItem(Mvf_Function_t *, mvfRoots2, i, func2) {
00296     Mvf_FunctionFree(func2);
00297   }
00298   array_free(mvfRoots2);
00299   Ntk_NetworkSetMddManager(network2, NIL(mdd_manager));
00300   /*
00301    * This is needed because Ntk_NetworkFree() will be called on both network1
00302    * and network2.
00303    */
00304   return equivalent;
00305 }
00306 
00329 boolean
00330 Eqv_NetworkVerifySequentialEquivalence(
00331   Ntk_Network_t *network1,
00332   Ntk_Network_t *network2,
00333   st_table *rootsTable,    /* the mapping between the outputs of the networks;
00334                             * hash table from char * to char * */
00335   st_table *leavesTable,   /* the mapping between the inputs of the networks;
00336                             * hash table from char * to char * */
00337   Part_PartitionMethod partMethod,
00338   boolean useBackwardReach,
00339   boolean reordering)
00340 {
00341   array_t *roots;
00342   st_table *leaves;
00343   lsList rootsList;
00344   lsList rootsPartList = (lsList) 0;
00345   st_table *outputMap = NIL(st_table);
00346   Ntk_Node_t *node1, *node2, *node;
00347   char *name1, *name2, *temp;
00348   st_generator *gen;
00349   lsGen listGen;
00350   graph_t *partition;
00351   vertex_t *vertex;
00352   mdd_manager *mddMgr;
00353   array_t *mvfArray;
00354   Mvf_Function_t *mvf1, *mvf2;
00355   mdd_t *badStates, *initialStates;
00356   mdd_t *mddTemp, *mdd1, *mdd2, *tautology;
00357   mdd_t *mddComp1, *mddComp2;
00358   int n, i, j, numComponents;
00359   int id;
00360   array_t *inputIdArray;
00361   lsList dummy = (lsList) 0;
00362   lsGeneric data;
00363   Ntk_Node_t *input;
00364   Fsm_Fsm_t *modelFsm;
00365   array_t *onionRings;
00366   array_t *aPath;
00367   boolean inequivalent;
00368   boolean rootsFlag = (rootsTable == NIL(st_table)) ? FALSE : TRUE;
00369   array_t *careStatesArray = array_alloc(mdd_t *, 0);
00370 
00371   /* If rootsFlag is FALSE, all primary outputs are to be verified */
00372   if(rootsFlag == FALSE) {
00373     outputMap = MapPrimaryOutputsByName(network1, network2);
00374   }
00375 
00376   /*
00377    * If leavesFlag is FALSE, the primary inputs in the two networks are
00378    * assumed to have same names. In the network returned by
00379    * Ntk_NetworkAppendNetwork(), the two corresponding nodes will be merged.
00380    * If leavesFlag is TRUE, the name correspondence between the primary inputs
00381    * in the two networks is specified in leavesTable.
00382    */
00383   if(leavesTable == NIL(st_table)) {
00384     st_table *emptyTable = st_init_table(strcmp, st_strhash);
00385     Ntk_NetworkAppendNetwork(network2, network1, emptyTable);
00386     st_free_table(emptyTable);
00387   }
00388   else {
00389     Ntk_NetworkAppendNetwork(network2, network1, leavesTable);
00390   }
00391 
00392   /*
00393    * network1 has been appended to the erstwhile network2, and the new network
00394    * is now called network2.
00395    */
00396 
00397   mddMgr = Ntk_NetworkInitializeMddManager(network2);
00398 
00399   Ord_NetworkOrderVariables(network2, Ord_RootsByDefault_c,
00400                             Ord_NodesByDefault_c, FALSE, Ord_InputAndLatch_c,
00401                             Ord_Unassigned_c, dummy, FALSE);
00402 
00403   if (reordering)
00404     Ntk_NetworkSetDynamicVarOrderingMethod(network2, BDD_REORDER_SIFT,
00405                                            BDD_REORDER_VERBOSITY);
00406   /*
00407    * Ntk_NetworkAppendNetwork() adds $NTK2 to the names of all the
00408    * appended nodes. I want to find the appended nodes in new network2
00409    * corresponding to the roots in network1. I will add all these nodes to
00410    * rootsList. I will also add all the roots of the erstwhile network2, which
00411    * exist in the network2 also. rootsList will finally contain all the nodes
00412    * in network2 whose mdds have to be created by Part_Partition Collapse().
00413    */
00414 
00415   rootsList = lsCreate();
00416   if(rootsFlag == FALSE) {
00417     st_foreach_item(outputMap, gen, &node1, &node2) {
00418       name1 = Ntk_NodeReadName(node1);
00419       temp = util_strcat3(name1, "$NTK2", "");
00420       name1 = temp;
00421       node1 = Ntk_NetworkFindNodeByName(network2, name1);
00422       assert(node1 != NIL(Ntk_Node_t));
00423       FREE(name1);
00424       lsNewEnd(rootsList, (lsGeneric) node1, LS_NH);
00425       lsNewEnd(rootsList, (lsGeneric) node2, LS_NH);
00426     }
00427   }
00428   else {
00429     st_foreach_item(rootsTable, gen, &name1, &name2) {
00430       /* I am finding the node in the new network2 */
00431       temp = util_strcat3(name1, "$NTK2", "");
00432       name1 = temp;
00433       node1 = Ntk_NetworkFindNodeByName(network2, name1);
00434       FREE(name1);
00435       lsNewEnd(rootsList, (lsGeneric) node1, LS_NH);
00436       node2 = Ntk_NetworkFindNodeByName(network2, name2);
00437       lsNewEnd(rootsList, (lsGeneric) node2, LS_NH);
00438     }
00439   }
00440   if(outputMap) {
00441     st_free_table(outputMap);
00442   }
00443   /* rootsPartList is the list of nodes which will passed to
00444    * Part_NetworkCreatePartition(). I want all the next state functions i.e.
00445    * latch data inputs as well as everything in rootsList to be in
00446    * rootsPartList. If rootsFlag is FALSE, rootsPartList is simply passed as
00447    * (lsList) 0.
00448    */
00449   if(rootsFlag) {
00450     rootsPartList = lsCreate();
00451     Ntk_NetworkForEachCombOutput(network2, listGen, node) {
00452       if(Ntk_NodeTestIsLatchDataInput(node) ||
00453          Ntk_NodeTestIsLatchInitialInput(node)){
00454         lsNewEnd(rootsPartList, (lsGeneric) node, LS_NH);
00455       }
00456     }
00457     lsForEachItem(rootsList, listGen, node) {
00458       if(!Ntk_NodeTestIsLatchDataInput(node) &&
00459          !Ntk_NodeTestIsLatchInitialInput(node)) {
00460         lsNewEnd(rootsPartList, (lsGeneric) node, LS_NH);
00461       }
00462     }
00463   }
00464   partition = Part_NetworkCreatePartition(network2, NIL(Hrc_Node_t), "dummy",
00465                                           rootsPartList,
00466                                           (lsList) 0, NIL(mdd_t), partMethod,
00467                                           dummy, FALSE, FALSE, TRUE);
00468 
00469   Ntk_NetworkAddApplInfo(network2, PART_NETWORK_APPL_KEY,
00470                          (Ntk_ApplInfoFreeFn) Part_PartitionFreeCallback,
00471                          (void *) partition);
00472   if(rootsPartList) {
00473     lsDestroy(rootsPartList, (void (*) (lsGeneric)) 0);
00474   }
00475   /* Create roots and leaves for Part_PartitionCollapse().
00476    */
00477   roots = array_alloc(vertex_t *, 0);
00478   lsForEachItem(rootsList, listGen, data) {
00479     name1 = Ntk_NodeReadName((Ntk_Node_t *) data);
00480     vertex = Part_PartitionFindVertexByName(partition, name1);
00481     assert(vertex != NIL(vertex_t));
00482     array_insert_last(vertex_t *, roots, vertex);
00483   }
00484   lsDestroy(rootsList, (void (*) (lsGeneric)) 0);
00485   leaves = st_init_table(st_ptrcmp, st_ptrhash);
00486   Ntk_NetworkForEachCombInput(network2, listGen, node1) {
00487     name1 = Ntk_NodeReadName(node1);
00488     vertex = Part_PartitionFindVertexByName(partition, name1);
00489     if(vertex != NIL(vertex_t)) {
00490       /* A combinational input might not be present in the support of any
00491          node in rootsPartList. If so, it will not be present in the partition
00492          also. */
00493       st_insert(leaves, (char *) vertex, (char *) (long) 0);
00494     }
00495   }
00496   mvfArray = Part_PartitionCollapse(partition, roots, leaves, NIL(mdd_t));
00497   array_free(roots);
00498   st_free_table(leaves);
00499   n = array_n(mvfArray);
00500   assert(n%2 == 0);
00501   n = n/2;
00502   assert(mddMgr != NULL);
00503 
00504 /* In mvfArray, the mvfs of corresponding nodes occur one after the other,
00505    * because of the way rootsList was created. badStates will ultimately
00506    * contain all the states for which  any pair of corresponding nodes differ
00507    * for some input.
00508    */
00509   badStates = mdd_zero(mddMgr);
00510   for(i=0; i<n; i++) {
00511     mvf1 = array_fetch(Mvf_Function_t *, mvfArray, 2*i);
00512     mvf2 = array_fetch(Mvf_Function_t *, mvfArray, 2*i +1);
00513     numComponents = Mvf_FunctionReadNumComponents(mvf1);
00514     mdd2 = mdd_zero(mddMgr);
00515     /*
00516      * Hopefully, mddMgr of the partition is the same as the mddMgr of the
00517      * MVFs.
00518      */
00519     for(j=0; j<numComponents; j++) {
00520       mddComp1 = Mvf_FunctionObtainComponent(mvf1, j);
00521       mddComp2 = Mvf_FunctionObtainComponent(mvf2, j);
00522       mdd1 = mdd_and(mddComp1, mddComp2, 1, 1);
00523       mdd_free(mddComp1);
00524       mdd_free(mddComp2);
00525       mddTemp = mdd_or(mdd2, mdd1, 1, 1);
00526       mdd_free(mdd1);
00527       mdd_free(mdd2);
00528       mdd2 = mddTemp;
00529     }
00530 
00531    /*
00532     * At this point, mdd2 represents the set of input and present state
00533     * combinations in which mvf1 and mvf2 produce the same value. I want the
00534     * set for which mvf1 and mvf2 are different.
00535     */
00536     mddTemp = mdd_or(badStates, mdd2, 1, 0);
00537     mdd_free(mdd2);
00538     mdd_free(badStates);
00539     badStates = mddTemp;
00540   }
00541   arrayForEachItem(Mvf_Function_t *, mvfArray, i, mvf1) {
00542     Mvf_FunctionFree(mvf1);
00543   }
00544   array_free(mvfArray);
00545   /* existentially quantify out the input variables */
00546   inputIdArray = array_alloc(int, 0);
00547 
00548   Ntk_NetworkForEachPrimaryInput(network2, listGen, input) {
00549     id = Ntk_NodeReadMddId(input);
00550     assert(id >= 0);
00551     array_insert_last(int, inputIdArray, id);
00552   }
00553 
00554   mddTemp = mdd_smooth(mddMgr, badStates, inputIdArray);
00555   mdd_free(badStates);
00556   badStates = mddTemp;
00557   array_free(inputIdArray);
00558   modelFsm = Fsm_FsmCreateFromNetworkWithPartition(network2, NIL(graph_t));
00559   assert(modelFsm != NIL(Fsm_Fsm_t));
00560   Ntk_NetworkAddApplInfo(network2, FSM_NETWORK_APPL_KEY,
00561                          (Ntk_ApplInfoFreeFn) Fsm_FsmFreeCallback,
00562                          (void *) modelFsm);
00563 
00564   onionRings = array_alloc(mdd_t *, 0);
00565   initialStates = Fsm_FsmComputeInitialStates(modelFsm);
00566   tautology = mdd_one(mddMgr);
00567 
00568   /* Model checking function */
00569   if (useBackwardReach == TRUE) {
00570     array_insert(mdd_t *, careStatesArray, 0, tautology);
00571     inequivalent = Mc_FsmComputeStatesReachingToSet(modelFsm, badStates,
00572                         careStatesArray, initialStates,
00573                         onionRings, McVerbosityNone_c, McDcLevelNone_c);
00574     array_free(careStatesArray);
00575     mdd_free(badStates);
00576     mdd_free(tautology);
00577 
00578     if (inequivalent) {
00579       mdd_t *outerOnionRing = array_fetch_last(mdd_t *, onionRings);
00580       mdd_t *badInitialStates = mdd_and(initialStates, outerOnionRing, 1, 1);
00581       array_t *psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm);
00582       mdd_t *aBadInitialState = Mc_ComputeAMinterm(initialStates, psVarMddIdArray, mddMgr);
00583       mdd_free(badInitialStates);
00584       aPath = Mc_BuildPathToCore(aBadInitialState, onionRings, modelFsm,
00585                                  McGreaterOrEqualZero_c);
00586       (void) Mc_PrintPath(aPath, modelFsm, TRUE); /* TRUE -> print inputs on path */
00587       mdd_free(aBadInitialState);
00588       mdd_free(initialStates);
00589       mdd_array_free(aPath);
00590       mdd_array_free(onionRings);
00591       return FALSE;
00592     }
00593     else {
00594       mdd_free(initialStates);
00595       return TRUE;
00596     }
00597   }
00598   else { /* do forward search */
00599     array_insert(mdd_t *, careStatesArray, 0, tautology);
00600     inequivalent = Mc_FsmComputeStatesReachableFromSet(modelFsm, initialStates,
00601                         careStatesArray, badStates, onionRings,
00602                         McVerbosityNone_c, McDcLevelNone_c);
00603     array_free(careStatesArray);
00604     mdd_free(tautology);
00605     mdd_free(initialStates);
00606 
00607     if (inequivalent) {
00608       mdd_t *outerOnionRing = array_fetch_last(mdd_t *, onionRings);
00609       mdd_t *reachableBadStates = mdd_and(badStates, outerOnionRing, 1, 1);
00610       array_t *psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm);
00611       mdd_t *aBadReachableState = Mc_ComputeAMinterm(reachableBadStates, psVarMddIdArray, mddMgr);
00612       mdd_free(reachableBadStates);
00613       psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm);
00614       aPath = Mc_BuildPathFromCore(aBadReachableState, onionRings, modelFsm,
00615                                  McGreaterOrEqualZero_c);
00616       (void) Mc_PrintPath(aPath, modelFsm, TRUE); /* TRUE -> print inputs on path */
00617       mdd_free(aBadReachableState);
00618       mdd_free(badStates);
00619       mdd_array_free(aPath);
00620       mdd_array_free(onionRings);
00621       return FALSE;
00622     }
00623     else {
00624       mdd_free(badStates);
00625       return TRUE;
00626     }
00627   }
00628 }
00629 
00630 /*---------------------------------------------------------------------------*/
00631 /* Definition of internal functions                                          */
00632 /*---------------------------------------------------------------------------*/
00633 
00634 
00635 /*---------------------------------------------------------------------------*/
00636 /* Definition of static functions                                            */
00637 /*---------------------------------------------------------------------------*/