[14] | 1 | /**CFile*********************************************************************** |
---|
| 2 | |
---|
| 3 | FileName [eqvVerify.c] |
---|
| 4 | |
---|
| 5 | PackageName [eqv] |
---|
| 6 | |
---|
| 7 | Synopsis [This file contains the two routines which do combinational and |
---|
| 8 | sequential verification.] |
---|
| 9 | |
---|
| 10 | Description [] |
---|
| 11 | |
---|
| 12 | SeeAlso [] |
---|
| 13 | |
---|
| 14 | Author [Shaz Qadeer] |
---|
| 15 | |
---|
| 16 | Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. |
---|
| 17 | All rights reserved. |
---|
| 18 | |
---|
| 19 | Permission is hereby granted, without written agreement and without license |
---|
| 20 | or royalty fees, to use, copy, modify, and distribute this software and its |
---|
| 21 | documentation for any purpose, provided that the above copyright notice and |
---|
| 22 | the following two paragraphs appear in all copies of this software. |
---|
| 23 | |
---|
| 24 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR |
---|
| 25 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
---|
| 26 | OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF |
---|
| 27 | CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
| 28 | |
---|
| 29 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
---|
| 30 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
---|
| 31 | FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN |
---|
| 32 | "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE |
---|
| 33 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] |
---|
| 34 | |
---|
| 35 | ******************************************************************************/ |
---|
| 36 | |
---|
| 37 | #include "eqvInt.h" |
---|
| 38 | |
---|
| 39 | static char rcsid[] UNUSED = "$Id: eqvVerify.c,v 1.10 2009/04/11 01:40:06 fabio Exp $"; |
---|
| 40 | |
---|
| 41 | /**AutomaticStart*************************************************************/ |
---|
| 42 | |
---|
| 43 | /*---------------------------------------------------------------------------*/ |
---|
| 44 | /* Static function prototypes */ |
---|
| 45 | /*---------------------------------------------------------------------------*/ |
---|
| 46 | |
---|
| 47 | |
---|
| 48 | /**AutomaticEnd***************************************************************/ |
---|
| 49 | |
---|
| 50 | |
---|
| 51 | /*---------------------------------------------------------------------------*/ |
---|
| 52 | /* Definition of exported functions */ |
---|
| 53 | /*---------------------------------------------------------------------------*/ |
---|
| 54 | |
---|
| 55 | /**Function******************************************************************** |
---|
| 56 | |
---|
| 57 | Synopsis [This function does combinational verification between network1 |
---|
| 58 | and network2.] |
---|
| 59 | |
---|
| 60 | Description [roootsMap and leavesMap contain corresponding nodes in network1 |
---|
| 61 | and network2. It is assumed that the set of leaf nodes forms a complete |
---|
| 62 | support of the set of root nodes in both the networks. This function |
---|
| 63 | verifies the combinational equivalence of corresponding roots in terms of |
---|
| 64 | the leaves. method1 and method2 specify the partition methods to be used for |
---|
| 65 | partitioning network1 and network2 respectively. AssignCommonOrder is a |
---|
| 66 | pointer to a function which takes two networks, whose mdd managers are |
---|
| 67 | identical, and a hash table containing corresponding leaf nodes whose mdd Id |
---|
| 68 | should be the same. AssignCommonOrder() orders the two networks ensuring |
---|
| 69 | that identical mddIds are assigned to the corresponding leaf nodes in the |
---|
| 70 | hash table. This function has to be supplied by the user. |
---|
| 71 | |
---|
| 72 | This function returns TRUE if all the root pairs are combinationally |
---|
| 73 | equivalent otherwise it returns FALSE. It is assumed that network1 already |
---|
| 74 | has a mdd manager. If a partition is registered with network1, and it has |
---|
| 75 | vertices corresponding to the specified roots and leaves it is used |
---|
| 76 | otherwise a new partition is created. A new partition is always created for |
---|
| 77 | network2.] |
---|
| 78 | |
---|
| 79 | SideEffects [] |
---|
| 80 | |
---|
| 81 | ******************************************************************************/ |
---|
| 82 | boolean |
---|
| 83 | Eqv_NetworkVerifyCombinationalEquivalence( |
---|
| 84 | Ntk_Network_t *network1, |
---|
| 85 | Ntk_Network_t *network2, |
---|
| 86 | st_table *leavesMap, /* the mapping between the inputs of the networks; |
---|
| 87 | * hash table from Ntk_Node_t * to Ntk_Node_t * */ |
---|
| 88 | st_table *rootsMap, /* the mapping between the outputs of the networks; |
---|
| 89 | * hash table from Ntk_Node_t * to Ntk_Node_t * */ |
---|
| 90 | OFT AssignCommonOrder, |
---|
| 91 | Part_PartitionMethod method1, |
---|
| 92 | Part_PartitionMethod method2) |
---|
| 93 | { |
---|
| 94 | mdd_manager *mddMgr; |
---|
| 95 | lsList leavesList1, leavesList2; |
---|
| 96 | lsList rootsList1, rootsList2; |
---|
| 97 | st_table *leaves1, *leaves2; |
---|
| 98 | array_t *roots1, *roots2; |
---|
| 99 | st_generator *gen; |
---|
| 100 | lsGen listGen; |
---|
| 101 | graph_t *rootsToLeaves1, *rootsToLeaves2; |
---|
| 102 | Ntk_Node_t *node1, *node2; |
---|
| 103 | char *name1, *name2, *name; |
---|
| 104 | Mvf_Function_t *func1, *func2; |
---|
| 105 | int num, i, j; |
---|
| 106 | array_t *mvfRoots1, *mvfRoots2; |
---|
| 107 | boolean equivalent = TRUE; |
---|
| 108 | lsList dummy = (lsList) 0; |
---|
| 109 | int mddId1, mddId2; |
---|
| 110 | vertex_t *vertex; |
---|
| 111 | lsGeneric data; |
---|
| 112 | boolean partValid = FALSE; |
---|
| 113 | mdd_manager *mgr; |
---|
| 114 | int mddId; |
---|
| 115 | array_t *mddIdArray; |
---|
| 116 | mdd_t *aMinterm, *diff; |
---|
| 117 | char *mintermName; |
---|
| 118 | mdd_t *comp1, *comp2; |
---|
| 119 | int numComponents; |
---|
| 120 | |
---|
| 121 | /* First check whether a partition is registered with network1 */ |
---|
| 122 | if(Ntk_NetworkReadApplInfo(network1, PART_NETWORK_APPL_KEY) != NIL(void)) { |
---|
| 123 | /* |
---|
| 124 | * Check whether the registered partition can be used to compute the roots |
---|
| 125 | * in terms of the leaves. If it can be used, then i won't create a new |
---|
| 126 | * one. |
---|
| 127 | */ |
---|
| 128 | partValid = TestPartitionIsValid(network1, rootsMap, leavesMap); |
---|
| 129 | /* |
---|
| 130 | * If a partition already exists, an mddManager also exists. |
---|
| 131 | * So, don't allocate a new one. |
---|
| 132 | */ |
---|
| 133 | mddMgr = Ntk_NetworkReadMddManager(network1); |
---|
| 134 | } |
---|
| 135 | else { |
---|
| 136 | mddMgr = Ntk_NetworkInitializeMddManager(network1); |
---|
| 137 | } |
---|
| 138 | assert(mddMgr != NIL(mdd_manager)); |
---|
| 139 | Ntk_NetworkSetMddManager(network2, mddMgr); |
---|
| 140 | (*AssignCommonOrder)(network1, network2, leavesMap); |
---|
| 141 | |
---|
| 142 | /* Create lists of leaves and roots for creating partitions. */ |
---|
| 143 | leavesList1 = lsCreate(); |
---|
| 144 | leavesList2 = lsCreate(); |
---|
| 145 | st_foreach_item(leavesMap, gen, &node1, &node2) { |
---|
| 146 | mddId1 = Ntk_NodeReadMddId(node1); |
---|
| 147 | mddId2 = Ntk_NodeReadMddId(node2); |
---|
| 148 | assert(mddId1 == mddId2); |
---|
| 149 | lsNewEnd(leavesList1, (lsGeneric) node1, LS_NH); |
---|
| 150 | lsNewEnd(leavesList2, (lsGeneric) node2, LS_NH); |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | rootsList1 = lsCreate(); |
---|
| 154 | rootsList2 = lsCreate(); |
---|
| 155 | st_foreach_item(rootsMap, gen, &node1, &node2) { |
---|
| 156 | lsNewEnd(rootsList1, (lsGeneric) node1, LS_NH); |
---|
| 157 | lsNewEnd(rootsList2, (lsGeneric) node2, LS_NH); |
---|
| 158 | } |
---|
| 159 | |
---|
| 160 | if(partValid) { |
---|
| 161 | rootsToLeaves1 = Part_NetworkReadPartition(network1); |
---|
| 162 | } |
---|
| 163 | else { |
---|
| 164 | rootsToLeaves1 = Part_NetworkCreatePartition(network1, NIL(Hrc_Node_t), |
---|
| 165 | "dummy", rootsList1, |
---|
| 166 | leavesList1, NIL(mdd_t), |
---|
| 167 | method1, dummy, |
---|
| 168 | FALSE, FALSE, TRUE); |
---|
| 169 | } |
---|
| 170 | |
---|
| 171 | /* |
---|
| 172 | * Generate arrays of root and leaf vertices in the first partition |
---|
| 173 | * to pass as arguments to Part_PartitionCollapse(). |
---|
| 174 | */ |
---|
| 175 | roots1 = array_alloc(vertex_t *, 0); |
---|
| 176 | lsForEachItem(rootsList1, listGen, data) { |
---|
| 177 | name = Ntk_NodeReadName((Ntk_Node_t *) data); |
---|
| 178 | vertex = Part_PartitionFindVertexByName(rootsToLeaves1, name); |
---|
| 179 | assert(vertex != NIL(vertex_t)); |
---|
| 180 | array_insert_last(vertex_t *, roots1, vertex); |
---|
| 181 | } |
---|
| 182 | leaves1 = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 183 | lsForEachItem(leavesList1, listGen, data) { |
---|
| 184 | name = Ntk_NodeReadName((Ntk_Node_t *) data); |
---|
| 185 | vertex = Part_PartitionFindVertexByName(rootsToLeaves1, name); |
---|
| 186 | /* assert(vertex != NIL(vertex_t)); */ |
---|
| 187 | if(vertex != NIL(vertex_t)) { |
---|
| 188 | /* |
---|
| 189 | * If a leaf is not actually in the support of the roots then |
---|
| 190 | * it will not be present in the partition. |
---|
| 191 | */ |
---|
| 192 | mddId = Part_VertexReadMddId(vertex); |
---|
| 193 | st_insert(leaves1, (char *) vertex, (char *) (long) mddId); |
---|
| 194 | } |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | lsDestroy(rootsList1, (void (*) (lsGeneric)) 0); |
---|
| 198 | lsDestroy(leavesList1, (void (*) (lsGeneric)) 0); |
---|
| 199 | rootsToLeaves2 = Part_NetworkCreatePartition(network2, NIL(Hrc_Node_t), |
---|
| 200 | "dummy", rootsList2, |
---|
| 201 | leavesList2, NIL(mdd_t), |
---|
| 202 | method2, dummy, FALSE, |
---|
| 203 | FALSE, TRUE); |
---|
| 204 | |
---|
| 205 | /* |
---|
| 206 | * Generate arrays of root and leaf vertices in the second partition |
---|
| 207 | * to pass as arguments to Part_PartitionCollapse(). |
---|
| 208 | */ |
---|
| 209 | roots2 = array_alloc(vertex_t *, 0); |
---|
| 210 | lsForEachItem(rootsList2, listGen, data) { |
---|
| 211 | name = Ntk_NodeReadName((Ntk_Node_t *) data); |
---|
| 212 | vertex = Part_PartitionFindVertexByName(rootsToLeaves2, name); |
---|
| 213 | assert(vertex != NIL(vertex_t)); |
---|
| 214 | array_insert_last(vertex_t *, roots2, vertex); |
---|
| 215 | } |
---|
| 216 | leaves2 = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 217 | lsForEachItem(leavesList2, listGen, data) { |
---|
| 218 | name = Ntk_NodeReadName((Ntk_Node_t *) data); |
---|
| 219 | vertex = Part_PartitionFindVertexByName(rootsToLeaves2, name); |
---|
| 220 | /* assert(vertex != NIL(vertex_t)); */ |
---|
| 221 | if(vertex != NIL(vertex_t)) { |
---|
| 222 | /* |
---|
| 223 | * If a leaf is not actually in the support of the roots then |
---|
| 224 | * it will not be present in the partition. |
---|
| 225 | */ |
---|
| 226 | mddId = Part_VertexReadMddId(vertex); |
---|
| 227 | st_insert(leaves2, (char *) vertex, (char *) (long) mddId); |
---|
| 228 | } |
---|
| 229 | } |
---|
| 230 | lsDestroy(rootsList2, (void (*) (lsGeneric)) 0); |
---|
| 231 | lsDestroy(leavesList2, (void (*) (lsGeneric)) 0); |
---|
| 232 | assert(Part_PartitionReadMddManager(rootsToLeaves1) == |
---|
| 233 | Part_PartitionReadMddManager(rootsToLeaves2)); |
---|
| 234 | |
---|
| 235 | mvfRoots1 = Part_PartitionCollapse(rootsToLeaves1, roots1, leaves1, NIL(mdd_t)); |
---|
| 236 | mvfRoots2 = Part_PartitionCollapse(rootsToLeaves2, roots2, leaves2, NIL(mdd_t)); |
---|
| 237 | |
---|
| 238 | assert(array_n(mvfRoots1) == array_n(mvfRoots2)); |
---|
| 239 | num = array_n(mvfRoots1); |
---|
| 240 | mddIdArray = array_alloc(int, 0); |
---|
| 241 | st_foreach_item_int(leaves1, gen, &vertex, &mddId) { |
---|
| 242 | array_insert_last(int, mddIdArray, mddId); |
---|
| 243 | } |
---|
| 244 | |
---|
| 245 | /* |
---|
| 246 | * For each pair of corresponding outputs in the two arrays mvfRoots1 and |
---|
| 247 | * mvfRoots2, I will compute the mdd representing all the input combinations |
---|
| 248 | * for which they are different. For each pair, I will print one input |
---|
| 249 | * combination for which they are different. |
---|
| 250 | */ |
---|
| 251 | |
---|
| 252 | for(i = 0; i<num; ++i) { |
---|
| 253 | func1 = array_fetch(Mvf_Function_t *, mvfRoots1, i); |
---|
| 254 | func2 = array_fetch(Mvf_Function_t *, mvfRoots2, i); |
---|
| 255 | if(!Mvf_FunctionTestIsEqualToFunction(func1, func2)) { |
---|
| 256 | mgr = Mvf_FunctionReadMddManager(func1); |
---|
| 257 | assert(mgr == Mvf_FunctionReadMddManager(func2)); |
---|
| 258 | numComponents = Mvf_FunctionReadNumComponents(func1); |
---|
| 259 | for(j=0; j<numComponents; ++j) { |
---|
| 260 | comp1 = Mvf_FunctionReadComponent(func1, j); |
---|
| 261 | comp2 = Mvf_FunctionReadComponent(func2, j); |
---|
| 262 | diff = mdd_xor(comp1, comp2); |
---|
| 263 | if(!mdd_is_tautology(diff, 0)) { |
---|
| 264 | aMinterm = Mc_ComputeAMinterm(diff, mddIdArray, mddMgr); |
---|
| 265 | mintermName = Mc_MintermToString(aMinterm, mddIdArray, network1); |
---|
| 266 | vertex = array_fetch(vertex_t *, roots1, i); |
---|
| 267 | name1 = Part_VertexReadName(vertex); |
---|
| 268 | vertex = array_fetch(vertex_t *, roots2, i); |
---|
| 269 | name2 = Part_VertexReadName(vertex); |
---|
| 270 | (void) fprintf(vis_stdout, "%s from network1 and %s from network2 differ on input values\n%s", |
---|
| 271 | name1, name2, mintermName); |
---|
| 272 | FREE(mintermName); |
---|
| 273 | mdd_free(aMinterm); |
---|
| 274 | mdd_free(diff); |
---|
| 275 | break; |
---|
| 276 | } |
---|
| 277 | mdd_free(diff); |
---|
| 278 | } |
---|
| 279 | equivalent = FALSE; |
---|
| 280 | } |
---|
| 281 | } |
---|
| 282 | array_free(mddIdArray); |
---|
| 283 | if(!partValid) { |
---|
| 284 | Part_PartitionFree(rootsToLeaves1); |
---|
| 285 | } |
---|
| 286 | Part_PartitionFree(rootsToLeaves2); |
---|
| 287 | array_free(roots1); |
---|
| 288 | array_free(roots2); |
---|
| 289 | st_free_table(leaves1); |
---|
| 290 | st_free_table(leaves2); |
---|
| 291 | arrayForEachItem(Mvf_Function_t *, mvfRoots1, i, func1) { |
---|
| 292 | Mvf_FunctionFree(func1); |
---|
| 293 | } |
---|
| 294 | array_free(mvfRoots1); |
---|
| 295 | arrayForEachItem(Mvf_Function_t *, mvfRoots2, i, func2) { |
---|
| 296 | Mvf_FunctionFree(func2); |
---|
| 297 | } |
---|
| 298 | array_free(mvfRoots2); |
---|
| 299 | Ntk_NetworkSetMddManager(network2, NIL(mdd_manager)); |
---|
| 300 | /* |
---|
| 301 | * This is needed because Ntk_NetworkFree() will be called on both network1 |
---|
| 302 | * and network2. |
---|
| 303 | */ |
---|
| 304 | return equivalent; |
---|
| 305 | } |
---|
| 306 | |
---|
| 307 | /**Function******************************************************************** |
---|
| 308 | |
---|
| 309 | Synopsis [This function does sequential verification between network1 and |
---|
| 310 | network2.] |
---|
| 311 | |
---|
| 312 | Description [It accepts as input the two networks, and two hash tables of |
---|
| 313 | node names - rootsTable and leavesTable. leavesTable gives the names of |
---|
| 314 | corresponding primary inputs in the two networks. If leavesTable is NULL, |
---|
| 315 | the inputs are simply matched by names. rootsTable gives the names of |
---|
| 316 | corresponding nodes in the two networks whose sequential equivalence has to |
---|
| 317 | be verified. If rootsTable is NULL, it is assumed that all the |
---|
| 318 | primary outputs need to be verified and that they are to be associated by |
---|
| 319 | names. The function returns TRUE if the all the corresponding nodes are |
---|
| 320 | sequentially equivalent otherwise it returns FALSE. The verification is done |
---|
| 321 | by appending network1 to network2, thereby forming the product machine. A |
---|
| 322 | set of states in which the corresponding outputs to be verified are |
---|
| 323 | different for some input is calculated and it is checked whether any of |
---|
| 324 | these states is reachable from an initial state of the product machine.] |
---|
| 325 | |
---|
| 326 | SideEffects [network2 is modified in this function.] |
---|
| 327 | |
---|
| 328 | ******************************************************************************/ |
---|
| 329 | boolean |
---|
| 330 | Eqv_NetworkVerifySequentialEquivalence( |
---|
| 331 | Ntk_Network_t *network1, |
---|
| 332 | Ntk_Network_t *network2, |
---|
| 333 | st_table *rootsTable, /* the mapping between the outputs of the networks; |
---|
| 334 | * hash table from char * to char * */ |
---|
| 335 | st_table *leavesTable, /* the mapping between the inputs of the networks; |
---|
| 336 | * hash table from char * to char * */ |
---|
| 337 | Part_PartitionMethod partMethod, |
---|
| 338 | boolean useBackwardReach, |
---|
| 339 | boolean reordering) |
---|
| 340 | { |
---|
| 341 | array_t *roots; |
---|
| 342 | st_table *leaves; |
---|
| 343 | lsList rootsList; |
---|
| 344 | lsList rootsPartList = (lsList) 0; |
---|
| 345 | st_table *outputMap = NIL(st_table); |
---|
| 346 | Ntk_Node_t *node1, *node2, *node; |
---|
| 347 | char *name1, *name2, *temp; |
---|
| 348 | st_generator *gen; |
---|
| 349 | lsGen listGen; |
---|
| 350 | graph_t *partition; |
---|
| 351 | vertex_t *vertex; |
---|
| 352 | mdd_manager *mddMgr; |
---|
| 353 | array_t *mvfArray; |
---|
| 354 | Mvf_Function_t *mvf1, *mvf2; |
---|
| 355 | mdd_t *badStates, *initialStates; |
---|
| 356 | mdd_t *mddTemp, *mdd1, *mdd2, *tautology; |
---|
| 357 | mdd_t *mddComp1, *mddComp2; |
---|
| 358 | int n, i, j, numComponents; |
---|
| 359 | int id; |
---|
| 360 | array_t *inputIdArray; |
---|
| 361 | lsList dummy = (lsList) 0; |
---|
| 362 | lsGeneric data; |
---|
| 363 | Ntk_Node_t *input; |
---|
| 364 | Fsm_Fsm_t *modelFsm; |
---|
| 365 | array_t *onionRings; |
---|
| 366 | array_t *aPath; |
---|
| 367 | boolean inequivalent; |
---|
| 368 | boolean rootsFlag = (rootsTable == NIL(st_table)) ? FALSE : TRUE; |
---|
| 369 | array_t *careStatesArray = array_alloc(mdd_t *, 0); |
---|
| 370 | |
---|
| 371 | /* If rootsFlag is FALSE, all primary outputs are to be verified */ |
---|
| 372 | if(rootsFlag == FALSE) { |
---|
| 373 | outputMap = MapPrimaryOutputsByName(network1, network2); |
---|
| 374 | } |
---|
| 375 | |
---|
| 376 | /* |
---|
| 377 | * If leavesFlag is FALSE, the primary inputs in the two networks are |
---|
| 378 | * assumed to have same names. In the network returned by |
---|
| 379 | * Ntk_NetworkAppendNetwork(), the two corresponding nodes will be merged. |
---|
| 380 | * If leavesFlag is TRUE, the name correspondence between the primary inputs |
---|
| 381 | * in the two networks is specified in leavesTable. |
---|
| 382 | */ |
---|
| 383 | if(leavesTable == NIL(st_table)) { |
---|
| 384 | st_table *emptyTable = st_init_table(strcmp, st_strhash); |
---|
| 385 | Ntk_NetworkAppendNetwork(network2, network1, emptyTable); |
---|
| 386 | st_free_table(emptyTable); |
---|
| 387 | } |
---|
| 388 | else { |
---|
| 389 | Ntk_NetworkAppendNetwork(network2, network1, leavesTable); |
---|
| 390 | } |
---|
| 391 | |
---|
| 392 | /* |
---|
| 393 | * network1 has been appended to the erstwhile network2, and the new network |
---|
| 394 | * is now called network2. |
---|
| 395 | */ |
---|
| 396 | |
---|
| 397 | mddMgr = Ntk_NetworkInitializeMddManager(network2); |
---|
| 398 | |
---|
| 399 | Ord_NetworkOrderVariables(network2, Ord_RootsByDefault_c, |
---|
| 400 | Ord_NodesByDefault_c, FALSE, Ord_InputAndLatch_c, |
---|
| 401 | Ord_Unassigned_c, dummy, FALSE); |
---|
| 402 | |
---|
| 403 | if (reordering) |
---|
| 404 | Ntk_NetworkSetDynamicVarOrderingMethod(network2, BDD_REORDER_SIFT, |
---|
| 405 | BDD_REORDER_VERBOSITY); |
---|
| 406 | /* |
---|
| 407 | * Ntk_NetworkAppendNetwork() adds $NTK2 to the names of all the |
---|
| 408 | * appended nodes. I want to find the appended nodes in new network2 |
---|
| 409 | * corresponding to the roots in network1. I will add all these nodes to |
---|
| 410 | * rootsList. I will also add all the roots of the erstwhile network2, which |
---|
| 411 | * exist in the network2 also. rootsList will finally contain all the nodes |
---|
| 412 | * in network2 whose mdds have to be created by Part_Partition Collapse(). |
---|
| 413 | */ |
---|
| 414 | |
---|
| 415 | rootsList = lsCreate(); |
---|
| 416 | if(rootsFlag == FALSE) { |
---|
| 417 | st_foreach_item(outputMap, gen, &node1, &node2) { |
---|
| 418 | name1 = Ntk_NodeReadName(node1); |
---|
| 419 | temp = util_strcat3(name1, "$NTK2", ""); |
---|
| 420 | name1 = temp; |
---|
| 421 | node1 = Ntk_NetworkFindNodeByName(network2, name1); |
---|
| 422 | assert(node1 != NIL(Ntk_Node_t)); |
---|
| 423 | FREE(name1); |
---|
| 424 | lsNewEnd(rootsList, (lsGeneric) node1, LS_NH); |
---|
| 425 | lsNewEnd(rootsList, (lsGeneric) node2, LS_NH); |
---|
| 426 | } |
---|
| 427 | } |
---|
| 428 | else { |
---|
| 429 | st_foreach_item(rootsTable, gen, &name1, &name2) { |
---|
| 430 | /* I am finding the node in the new network2 */ |
---|
| 431 | temp = util_strcat3(name1, "$NTK2", ""); |
---|
| 432 | name1 = temp; |
---|
| 433 | node1 = Ntk_NetworkFindNodeByName(network2, name1); |
---|
| 434 | FREE(name1); |
---|
| 435 | lsNewEnd(rootsList, (lsGeneric) node1, LS_NH); |
---|
| 436 | node2 = Ntk_NetworkFindNodeByName(network2, name2); |
---|
| 437 | lsNewEnd(rootsList, (lsGeneric) node2, LS_NH); |
---|
| 438 | } |
---|
| 439 | } |
---|
| 440 | if(outputMap) { |
---|
| 441 | st_free_table(outputMap); |
---|
| 442 | } |
---|
| 443 | /* rootsPartList is the list of nodes which will passed to |
---|
| 444 | * Part_NetworkCreatePartition(). I want all the next state functions i.e. |
---|
| 445 | * latch data inputs as well as everything in rootsList to be in |
---|
| 446 | * rootsPartList. If rootsFlag is FALSE, rootsPartList is simply passed as |
---|
| 447 | * (lsList) 0. |
---|
| 448 | */ |
---|
| 449 | if(rootsFlag) { |
---|
| 450 | rootsPartList = lsCreate(); |
---|
| 451 | Ntk_NetworkForEachCombOutput(network2, listGen, node) { |
---|
| 452 | if(Ntk_NodeTestIsLatchDataInput(node) || |
---|
| 453 | Ntk_NodeTestIsLatchInitialInput(node)){ |
---|
| 454 | lsNewEnd(rootsPartList, (lsGeneric) node, LS_NH); |
---|
| 455 | } |
---|
| 456 | } |
---|
| 457 | lsForEachItem(rootsList, listGen, node) { |
---|
| 458 | if(!Ntk_NodeTestIsLatchDataInput(node) && |
---|
| 459 | !Ntk_NodeTestIsLatchInitialInput(node)) { |
---|
| 460 | lsNewEnd(rootsPartList, (lsGeneric) node, LS_NH); |
---|
| 461 | } |
---|
| 462 | } |
---|
| 463 | } |
---|
| 464 | partition = Part_NetworkCreatePartition(network2, NIL(Hrc_Node_t), "dummy", |
---|
| 465 | rootsPartList, |
---|
| 466 | (lsList) 0, NIL(mdd_t), partMethod, |
---|
| 467 | dummy, FALSE, FALSE, TRUE); |
---|
| 468 | |
---|
| 469 | Ntk_NetworkAddApplInfo(network2, PART_NETWORK_APPL_KEY, |
---|
| 470 | (Ntk_ApplInfoFreeFn) Part_PartitionFreeCallback, |
---|
| 471 | (void *) partition); |
---|
| 472 | if(rootsPartList) { |
---|
| 473 | lsDestroy(rootsPartList, (void (*) (lsGeneric)) 0); |
---|
| 474 | } |
---|
| 475 | /* Create roots and leaves for Part_PartitionCollapse(). |
---|
| 476 | */ |
---|
| 477 | roots = array_alloc(vertex_t *, 0); |
---|
| 478 | lsForEachItem(rootsList, listGen, data) { |
---|
| 479 | name1 = Ntk_NodeReadName((Ntk_Node_t *) data); |
---|
| 480 | vertex = Part_PartitionFindVertexByName(partition, name1); |
---|
| 481 | assert(vertex != NIL(vertex_t)); |
---|
| 482 | array_insert_last(vertex_t *, roots, vertex); |
---|
| 483 | } |
---|
| 484 | lsDestroy(rootsList, (void (*) (lsGeneric)) 0); |
---|
| 485 | leaves = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 486 | Ntk_NetworkForEachCombInput(network2, listGen, node1) { |
---|
| 487 | name1 = Ntk_NodeReadName(node1); |
---|
| 488 | vertex = Part_PartitionFindVertexByName(partition, name1); |
---|
| 489 | if(vertex != NIL(vertex_t)) { |
---|
| 490 | /* A combinational input might not be present in the support of any |
---|
| 491 | node in rootsPartList. If so, it will not be present in the partition |
---|
| 492 | also. */ |
---|
| 493 | st_insert(leaves, (char *) vertex, (char *) (long) 0); |
---|
| 494 | } |
---|
| 495 | } |
---|
| 496 | mvfArray = Part_PartitionCollapse(partition, roots, leaves, NIL(mdd_t)); |
---|
| 497 | array_free(roots); |
---|
| 498 | st_free_table(leaves); |
---|
| 499 | n = array_n(mvfArray); |
---|
| 500 | assert(n%2 == 0); |
---|
| 501 | n = n/2; |
---|
| 502 | assert(mddMgr != NULL); |
---|
| 503 | |
---|
| 504 | /* In mvfArray, the mvfs of corresponding nodes occur one after the other, |
---|
| 505 | * because of the way rootsList was created. badStates will ultimately |
---|
| 506 | * contain all the states for which any pair of corresponding nodes differ |
---|
| 507 | * for some input. |
---|
| 508 | */ |
---|
| 509 | badStates = mdd_zero(mddMgr); |
---|
| 510 | for(i=0; i<n; i++) { |
---|
| 511 | mvf1 = array_fetch(Mvf_Function_t *, mvfArray, 2*i); |
---|
| 512 | mvf2 = array_fetch(Mvf_Function_t *, mvfArray, 2*i +1); |
---|
| 513 | numComponents = Mvf_FunctionReadNumComponents(mvf1); |
---|
| 514 | mdd2 = mdd_zero(mddMgr); |
---|
| 515 | /* |
---|
| 516 | * Hopefully, mddMgr of the partition is the same as the mddMgr of the |
---|
| 517 | * MVFs. |
---|
| 518 | */ |
---|
| 519 | for(j=0; j<numComponents; j++) { |
---|
| 520 | mddComp1 = Mvf_FunctionObtainComponent(mvf1, j); |
---|
| 521 | mddComp2 = Mvf_FunctionObtainComponent(mvf2, j); |
---|
| 522 | mdd1 = mdd_and(mddComp1, mddComp2, 1, 1); |
---|
| 523 | mdd_free(mddComp1); |
---|
| 524 | mdd_free(mddComp2); |
---|
| 525 | mddTemp = mdd_or(mdd2, mdd1, 1, 1); |
---|
| 526 | mdd_free(mdd1); |
---|
| 527 | mdd_free(mdd2); |
---|
| 528 | mdd2 = mddTemp; |
---|
| 529 | } |
---|
| 530 | |
---|
| 531 | /* |
---|
| 532 | * At this point, mdd2 represents the set of input and present state |
---|
| 533 | * combinations in which mvf1 and mvf2 produce the same value. I want the |
---|
| 534 | * set for which mvf1 and mvf2 are different. |
---|
| 535 | */ |
---|
| 536 | mddTemp = mdd_or(badStates, mdd2, 1, 0); |
---|
| 537 | mdd_free(mdd2); |
---|
| 538 | mdd_free(badStates); |
---|
| 539 | badStates = mddTemp; |
---|
| 540 | } |
---|
| 541 | arrayForEachItem(Mvf_Function_t *, mvfArray, i, mvf1) { |
---|
| 542 | Mvf_FunctionFree(mvf1); |
---|
| 543 | } |
---|
| 544 | array_free(mvfArray); |
---|
| 545 | /* existentially quantify out the input variables */ |
---|
| 546 | inputIdArray = array_alloc(int, 0); |
---|
| 547 | |
---|
| 548 | Ntk_NetworkForEachPrimaryInput(network2, listGen, input) { |
---|
| 549 | id = Ntk_NodeReadMddId(input); |
---|
| 550 | assert(id >= 0); |
---|
| 551 | array_insert_last(int, inputIdArray, id); |
---|
| 552 | } |
---|
| 553 | |
---|
| 554 | mddTemp = mdd_smooth(mddMgr, badStates, inputIdArray); |
---|
| 555 | mdd_free(badStates); |
---|
| 556 | badStates = mddTemp; |
---|
| 557 | array_free(inputIdArray); |
---|
| 558 | modelFsm = Fsm_FsmCreateFromNetworkWithPartition(network2, NIL(graph_t)); |
---|
| 559 | assert(modelFsm != NIL(Fsm_Fsm_t)); |
---|
| 560 | Ntk_NetworkAddApplInfo(network2, FSM_NETWORK_APPL_KEY, |
---|
| 561 | (Ntk_ApplInfoFreeFn) Fsm_FsmFreeCallback, |
---|
| 562 | (void *) modelFsm); |
---|
| 563 | |
---|
| 564 | onionRings = array_alloc(mdd_t *, 0); |
---|
| 565 | initialStates = Fsm_FsmComputeInitialStates(modelFsm); |
---|
| 566 | tautology = mdd_one(mddMgr); |
---|
| 567 | |
---|
| 568 | /* Model checking function */ |
---|
| 569 | if (useBackwardReach == TRUE) { |
---|
| 570 | array_insert(mdd_t *, careStatesArray, 0, tautology); |
---|
| 571 | inequivalent = Mc_FsmComputeStatesReachingToSet(modelFsm, badStates, |
---|
| 572 | careStatesArray, initialStates, |
---|
| 573 | onionRings, McVerbosityNone_c, McDcLevelNone_c); |
---|
| 574 | array_free(careStatesArray); |
---|
| 575 | mdd_free(badStates); |
---|
| 576 | mdd_free(tautology); |
---|
| 577 | |
---|
| 578 | if (inequivalent) { |
---|
| 579 | mdd_t *outerOnionRing = array_fetch_last(mdd_t *, onionRings); |
---|
| 580 | mdd_t *badInitialStates = mdd_and(initialStates, outerOnionRing, 1, 1); |
---|
| 581 | array_t *psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm); |
---|
| 582 | mdd_t *aBadInitialState = Mc_ComputeAMinterm(initialStates, psVarMddIdArray, mddMgr); |
---|
| 583 | mdd_free(badInitialStates); |
---|
| 584 | aPath = Mc_BuildPathToCore(aBadInitialState, onionRings, modelFsm, |
---|
| 585 | McGreaterOrEqualZero_c); |
---|
| 586 | (void) Mc_PrintPath(aPath, modelFsm, TRUE); /* TRUE -> print inputs on path */ |
---|
| 587 | mdd_free(aBadInitialState); |
---|
| 588 | mdd_free(initialStates); |
---|
| 589 | mdd_array_free(aPath); |
---|
| 590 | mdd_array_free(onionRings); |
---|
| 591 | return FALSE; |
---|
| 592 | } |
---|
| 593 | else { |
---|
| 594 | mdd_free(initialStates); |
---|
| 595 | return TRUE; |
---|
| 596 | } |
---|
| 597 | } |
---|
| 598 | else { /* do forward search */ |
---|
| 599 | array_insert(mdd_t *, careStatesArray, 0, tautology); |
---|
| 600 | inequivalent = Mc_FsmComputeStatesReachableFromSet(modelFsm, initialStates, |
---|
| 601 | careStatesArray, badStates, onionRings, |
---|
| 602 | McVerbosityNone_c, McDcLevelNone_c); |
---|
| 603 | array_free(careStatesArray); |
---|
| 604 | mdd_free(tautology); |
---|
| 605 | mdd_free(initialStates); |
---|
| 606 | |
---|
| 607 | if (inequivalent) { |
---|
| 608 | mdd_t *outerOnionRing = array_fetch_last(mdd_t *, onionRings); |
---|
| 609 | mdd_t *reachableBadStates = mdd_and(badStates, outerOnionRing, 1, 1); |
---|
| 610 | array_t *psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm); |
---|
| 611 | mdd_t *aBadReachableState = Mc_ComputeAMinterm(reachableBadStates, psVarMddIdArray, mddMgr); |
---|
| 612 | mdd_free(reachableBadStates); |
---|
| 613 | psVarMddIdArray = Fsm_FsmReadPresentStateVars(modelFsm); |
---|
| 614 | aPath = Mc_BuildPathFromCore(aBadReachableState, onionRings, modelFsm, |
---|
| 615 | McGreaterOrEqualZero_c); |
---|
| 616 | (void) Mc_PrintPath(aPath, modelFsm, TRUE); /* TRUE -> print inputs on path */ |
---|
| 617 | mdd_free(aBadReachableState); |
---|
| 618 | mdd_free(badStates); |
---|
| 619 | mdd_array_free(aPath); |
---|
| 620 | mdd_array_free(onionRings); |
---|
| 621 | return FALSE; |
---|
| 622 | } |
---|
| 623 | else { |
---|
| 624 | mdd_free(badStates); |
---|
| 625 | return TRUE; |
---|
| 626 | } |
---|
| 627 | } |
---|
| 628 | } |
---|
| 629 | |
---|
| 630 | /*---------------------------------------------------------------------------*/ |
---|
| 631 | /* Definition of internal functions */ |
---|
| 632 | /*---------------------------------------------------------------------------*/ |
---|
| 633 | |
---|
| 634 | |
---|
| 635 | /*---------------------------------------------------------------------------*/ |
---|
| 636 | /* Definition of static functions */ |
---|
| 637 | /*---------------------------------------------------------------------------*/ |
---|