VIS
|
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 /*---------------------------------------------------------------------------*/