VIS
|
00001 00032 #include "ntkInt.h" 00033 00034 static char rcsid[] UNUSED = "$Id: ntkFlt.c,v 1.13 2009/04/11 22:17:58 fabio Exp $"; 00035 00036 /*---------------------------------------------------------------------------*/ 00037 /* Constant declarations */ 00038 /*---------------------------------------------------------------------------*/ 00039 #define MAX_NUMBER_BDD_VARS 500 00040 00041 00042 /*---------------------------------------------------------------------------*/ 00043 /* Macro declarations */ 00044 /*---------------------------------------------------------------------------*/ 00045 00046 00049 /*---------------------------------------------------------------------------*/ 00050 /* Static function prototypes */ 00051 /*---------------------------------------------------------------------------*/ 00052 00053 static void NetworkBuildFormalToActualTableRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode); 00054 static void NetworkCreateNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode); 00055 static void NodeCreateAsNecessary(Ntk_Network_t *network, char *nodeName, Var_Variable_t *var); 00056 static boolean NetworkDeclareNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode, boolean buildMvfs, mdd_manager **mddMgr); 00057 static array_t * LocalArrayJoin(array_t *array1, array_t *array2); 00058 static array_t * TableCreateFormalInputNameArray(Tbl_Table_t *table, char *namePrefix); 00059 static void NameArrayFree(array_t *nameArray); 00060 static boolean NetworkAbstractNodes(Ntk_Network_t *network, lsList abstractedNames); 00061 static boolean NodeDeclareWithTable(Ntk_Node_t *node, Tbl_Table_t *table, int outIndex, char *path, boolean buildMvfs, mdd_manager *mddMgr); 00062 static void NetworkDeclareIONodes(Ntk_Network_t *network, Hrc_Node_t *hrcNode); 00063 static void NetworkDeclareLatches(Ntk_Network_t *network, Hrc_Node_t *hrcNode); 00064 static void MddManagerResetIfNecessary(mdd_manager **mddMgr); 00065 static Mvf_Function_t * LocalMvfFunctionForTable(Tbl_Table_t *table, int outIndex, mdd_manager *mddMgr, array_t *varMap, int *offset); 00066 00070 /*---------------------------------------------------------------------------*/ 00071 /* Definition of exported functions */ 00072 /*---------------------------------------------------------------------------*/ 00073 00117 Ntk_Network_t * 00118 Ntk_HrcNodeConvertToNetwork( 00119 Hrc_Node_t *hrcNode, 00120 boolean buildMvfs, 00121 lsList abstractedNames) 00122 { 00123 mdd_manager *mddMgr; 00124 boolean status1 = TRUE; 00125 boolean status2 = TRUE; 00126 char *hrcNodeName = Hrc_NodeReadInstanceName(hrcNode); 00127 Ntk_Network_t *network = Ntk_NetworkAlloc(hrcNodeName); 00128 00129 NetworkBuildFormalToActualTableRecursively(network, hrcNode); 00130 NetworkCreateNodesRecursively(network, hrcNode); 00131 00132 /* 00133 * The MDD manager is for building temporary MDDs. For robustness, enable 00134 * reordering. 00135 */ 00136 mddMgr = mdd_init_empty(); 00137 bdd_dynamic_reordering(mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT); 00138 status1 = NetworkDeclareNodesRecursively(network, hrcNode, buildMvfs, &mddMgr); 00139 mdd_quit(mddMgr); 00140 00141 if (abstractedNames != (lsList) NULL) { 00142 status2 = NetworkAbstractNodes(network, abstractedNames); 00143 } 00144 00145 if (!(status1 && status2)) { 00146 Ntk_NetworkFree(network); 00147 return NIL(Ntk_Network_t); 00148 } 00149 else { 00150 return network; 00151 } 00152 } 00153 00154 00155 /*---------------------------------------------------------------------------*/ 00156 /* Definition of internal functions */ 00157 /*---------------------------------------------------------------------------*/ 00158 00159 00160 /*---------------------------------------------------------------------------*/ 00161 /* Definition of static functions */ 00162 /*---------------------------------------------------------------------------*/ 00163 00164 00180 static void 00181 NetworkBuildFormalToActualTableRecursively( 00182 Ntk_Network_t *network, 00183 Hrc_Node_t *hrcNode) 00184 { 00185 st_generator *stGen; 00186 char *childName; 00187 Hrc_Node_t *childHrcNode; 00188 00189 /* 00190 * For each child of the current hnode, process its I/O variables, and 00191 * then recurse on its children. 00192 */ 00193 Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { 00194 00195 int i; 00196 array_t *childFormalInputs = Hrc_NodeReadFormalInputs(childHrcNode); 00197 array_t *childFormalOutputs = Hrc_NodeReadFormalOutputs(childHrcNode); 00198 array_t *childFormalIoArray = LocalArrayJoin(childFormalInputs, childFormalOutputs); 00199 00200 array_t *childActualInputs = Hrc_NodeReadActualInputs(childHrcNode); 00201 array_t *childActualOutputs = Hrc_NodeReadActualOutputs(childHrcNode); 00202 array_t *childActualIoArray = LocalArrayJoin(childActualInputs, childActualOutputs); 00203 00204 00205 /* 00206 * For each I/O variable, construct the appropriate hierarchical name for 00207 * the variable in childHrcNode (formalName) and the variable in the 00208 * hrcNode (actualName). If actualName already has a corresponding 00209 * actual, then use that, otherwise use actualName as is. Add 00210 * correspondence from formal (formalName) to actual (actualName). 00211 */ 00212 for(i = 0 ; i < array_n(childActualIoArray) ; i++) { 00213 Var_Variable_t *actualVar = array_fetch(Var_Variable_t *, childActualIoArray, i); 00214 Var_Variable_t *formalVar = array_fetch(Var_Variable_t *, childFormalIoArray, i); 00215 00216 char *nodeName = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); 00217 /* Special case the situation where hrcNode is current node. */ 00218 char *actualName = (strcmp(nodeName, "")) 00219 ? util_strcat3(nodeName, ".", 00220 Var_VariableReadName(actualVar)) 00221 : util_strsav(Var_VariableReadName(actualVar)); 00222 00223 char *childNodeName = Hrc_NodeFindHierarchicalName(childHrcNode, TRUE); 00224 char *formalName = util_strcat3(childNodeName, ".", 00225 Var_VariableReadName(formalVar)); 00226 00227 /* 00228 * It is correct to call this function with actualName. We want to 00229 * check if actualVar is itself a formalVar one level up. 00230 */ 00231 char *tempName = Ntk_NetworkReadActualNameFromFormalName(network, actualName); 00232 00233 FREE(nodeName); 00234 FREE(childNodeName); 00235 00236 /* 00237 * (tempName != NIL) => this net is a formal in hrcNode 00238 */ 00239 if (tempName != NIL(char)) { 00240 FREE(actualName); 00241 actualName = tempName; 00242 } 00243 00244 /* 00245 * Ntk_NetworkInsertFormalNameToActualName makes copies of the strings 00246 */ 00247 Ntk_NetworkInsertFormalNameToActualName(network, formalName, actualName); 00248 00249 if (tempName == NIL(char)) { 00250 FREE(actualName); 00251 } 00252 FREE(formalName); 00253 } 00254 array_free(childFormalIoArray); 00255 array_free(childActualIoArray); 00256 00257 /* 00258 * Recurse. 00259 */ 00260 NetworkBuildFormalToActualTableRecursively(network, childHrcNode); 00261 } 00262 } 00263 00264 00280 static void 00281 NetworkCreateNodesRecursively( 00282 Ntk_Network_t *network, 00283 Hrc_Node_t *hrcNode) 00284 { 00285 st_generator *stGen; 00286 Var_Variable_t *var; 00287 Hrc_Latch_t *latch; 00288 char *varName; 00289 char *latchName; 00290 char *childName; 00291 Hrc_Node_t *childHrcNode; 00292 char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); 00293 char *separator = (char *) ((strcmp(path, "")) ? "." : ""); 00294 00295 /* 00296 * The separator is used to handle the special case when hrcNode is the 00297 * current node in the hierarchy. If it is, we don't want a "." before the 00298 * variable names. 00299 */ 00300 00301 Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) { 00302 char *nodeName = util_strcat3(path, separator, varName); 00303 NodeCreateAsNecessary(network, nodeName, var); 00304 FREE(nodeName); 00305 } 00306 00307 /* 00308 * Variable for reset is the same as for present state. Hence, iterating 00309 * through the list of variables gets us just the present state. Therefore, 00310 * we need to special case the reset (or init) nodes. 00311 */ 00312 Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) { 00313 char *partialNodeName = util_strcat3(path, separator, latchName); 00314 char *nodeName = util_strcat3(partialNodeName, "$INIT", ""); 00315 00316 FREE(partialNodeName); 00317 NodeCreateAsNecessary(network, nodeName, Hrc_LatchReadOutput(latch)); 00318 FREE(nodeName); 00319 } 00320 FREE(path); 00321 00322 /* Recurse. */ 00323 Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { 00324 NetworkCreateNodesRecursively(network, childHrcNode); 00325 } 00326 } 00327 00328 00340 static void 00341 NodeCreateAsNecessary( 00342 Ntk_Network_t *network, 00343 char *nodeName, 00344 Var_Variable_t *var) 00345 { 00346 if (Ntk_NetworkFindNodeByName(network, nodeName)) { 00347 return; 00348 } 00349 00350 (void) Ntk_NodeCreateInNetwork(network, nodeName, var); 00351 } 00352 00353 00380 static boolean 00381 NetworkDeclareNodesRecursively( 00382 Ntk_Network_t *network, 00383 Hrc_Node_t *hrcNode, 00384 boolean buildMvfs, 00385 mdd_manager **mddMgr) 00386 { 00387 int i; 00388 st_generator *stGen; 00389 char *latchName; 00390 Var_Variable_t *var; 00391 Hrc_Latch_t *latch; 00392 Tbl_Table_t *table; 00393 char *childName; 00394 Hrc_Node_t *childHrcNode; 00395 boolean result = TRUE; 00396 char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); 00397 char *separator = (char *) ((strcmp(path, "")) ? "." : ""); 00398 00399 /* 00400 * First declare the network's PI/PO nodes. 00401 */ 00402 NetworkDeclareIONodes(network, hrcNode); 00403 00404 /* 00405 * Next, declare those nodes whose function is represented by a table. Note 00406 * that his iterator does not pick up those tables that define the 00407 * initialization logic of latches. 00408 */ 00409 Hrc_NodeForEachNameTable(hrcNode, i, table) { 00410 int index; 00411 Tbl_TableForEachOutputVar(table, index, var) { 00412 boolean status; 00413 char *fullVarName = util_strcat3(path, separator, 00414 Var_VariableReadName(var)); 00415 Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, fullVarName); 00416 00417 FREE(fullVarName); 00418 status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr); 00419 if (!status) { 00420 result = FALSE; 00421 } 00422 MddManagerResetIfNecessary(mddMgr); 00423 } 00424 } 00425 00426 /* 00427 * Declare each latch and its corresponding next state shadow node. 00428 */ 00429 NetworkDeclareLatches(network, hrcNode); 00430 00431 /* 00432 * Declare the "initial" node corresponding to each latch. 00433 */ 00434 Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) { 00435 int index; 00436 00437 table = Hrc_LatchReadResetTable(latch); 00438 00439 /* 00440 * There is only one output variable (the 0th output) for any table 00441 * defining the initial function of a latch, but we use an iterator to get 00442 * the variable for convenience. 00443 */ 00444 Tbl_TableForEachOutputVar(table, index, var) { 00445 boolean status; 00446 char *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var)); 00447 char *initName = util_strcat3(fullVarName, "$INIT", ""); 00448 Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, initName); 00449 00450 /* 00451 * Since the output of this table corresponds to a latch PS, can get name 00452 * of the initial node by attaching $INIT. 00453 */ 00454 FREE(fullVarName); 00455 FREE(initName); 00456 00457 status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr); 00458 if (!status) { 00459 result = FALSE; 00460 } 00461 MddManagerResetIfNecessary(mddMgr); 00462 } 00463 } 00464 FREE(path); 00465 00466 /* Recurse. */ 00467 Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { 00468 boolean status = NetworkDeclareNodesRecursively(network, childHrcNode, 00469 buildMvfs, mddMgr); 00470 if (!status) { 00471 result = FALSE; 00472 } 00473 } 00474 00475 return result; 00476 } 00477 00478 00492 static array_t * 00493 LocalArrayJoin( 00494 array_t *array1, 00495 array_t *array2) 00496 { 00497 if (array_n(array1) == 0) { 00498 return (array_dup(array2)); 00499 } 00500 else if (array_n(array2) == 0) { 00501 return (array_dup(array1)); 00502 } 00503 else { 00504 return (array_join(array1, array2)); 00505 } 00506 } 00507 00508 00525 static array_t * 00526 TableCreateFormalInputNameArray( 00527 Tbl_Table_t *table, 00528 char *namePrefix) 00529 { 00530 int index; 00531 array_t *nameArray; 00532 Var_Variable_t *var; 00533 char *separator = (char *) ((strcmp(namePrefix, "")) ? "." : ""); 00534 00535 /* 00536 * Allocate an array of length equal to the number of inputs of the table. 00537 * Then, for each input, add the full path name of the input to the array. 00538 */ 00539 nameArray = array_alloc(char *, Tbl_TableReadNumInputs(table)); 00540 Tbl_TableForEachInputVar(table, index, var) { 00541 char *inputFullName = util_strcat3(namePrefix, separator, Var_VariableReadName(var)); 00542 array_insert(char *, nameArray, index, inputFullName); 00543 } 00544 00545 return (nameArray); 00546 } 00547 00548 00558 static void 00559 NameArrayFree( 00560 array_t *nameArray) 00561 { 00562 int i; 00563 00564 for (i = 0; i < array_n(nameArray); i++) { 00565 char *name = array_fetch(char *, nameArray, i); 00566 FREE(name); 00567 } 00568 array_free(nameArray); 00569 } 00570 00585 static boolean 00586 NetworkAbstractNodes( 00587 Ntk_Network_t *network, 00588 lsList abstractedNames) 00589 { 00590 char *name; 00591 lsGen gen; 00592 00593 /* 00594 * For each abstracted name, cut the corresponding net, and introduce a new 00595 * node. 00596 */ 00597 lsForEachItem(abstractedNames, gen, name) { 00598 Var_Variable_t *var; 00599 Ntk_Node_t *abstractNode; 00600 array_t *abstractNodeFanouts; 00601 int i; 00602 Ntk_Node_t *fanout; 00603 char *abstractNodeName; 00604 Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, name); 00605 00606 /* Make sure the name corresponds to a node in the network. */ 00607 if (node == NIL(Ntk_Node_t)) { 00608 error_append("Could not find node corresponding to name: "); 00609 error_append(name); 00610 error_append("\n"); 00611 return FALSE; 00612 } 00613 00614 /* Create the new node in the network as a primary input. */ 00615 abstractNodeName = util_strcat3(name, "$ABS", ""); 00616 var = Ntk_NodeReadVariable(node); 00617 abstractNode = Ntk_NodeCreateInNetwork(network, abstractNodeName, var); 00618 FREE(abstractNodeName); 00619 Ntk_NodeDeclareAsPrimaryInput(abstractNode); 00620 00621 /* 00622 * For each fanout y of the node x being abstracted, replace x in y's 00623 * fanin list by the new node, and add y to the fanout list of the new 00624 * node. 00625 */ 00626 abstractNodeFanouts = Ntk_NodeReadFanouts(abstractNode); 00627 Ntk_NodeForEachFanout(node, i, fanout) { 00628 int index = Ntk_NodeReadFaninIndex(fanout, node); 00629 array_t *fanoutFanins = Ntk_NodeReadFanins(fanout); 00630 00631 array_insert(Ntk_Node_t *, fanoutFanins, index, abstractNode); 00632 array_insert_last(Ntk_Node_t *, abstractNodeFanouts, fanout); 00633 } 00634 00635 /* 00636 * Replace the fanout array of the node being abstracted with an empty 00637 * array. 00638 */ 00639 array_free(node->fanouts); 00640 node->fanouts = array_alloc(Ntk_Node_t *, 0); 00641 } 00642 00643 return TRUE; 00644 } 00645 00646 00674 static boolean 00675 NodeDeclareWithTable( 00676 Ntk_Node_t *node, 00677 Tbl_Table_t *table, 00678 int outIndex, 00679 char *path, 00680 boolean buildMvfs, 00681 mdd_manager *mddMgr) 00682 { 00683 Tbl_Table_t *newTable; 00684 int newOutIndex; 00685 boolean result = TRUE; 00686 char *nodeName = Ntk_NodeReadName(node); 00687 00688 /* 00689 * If table has no inputs and more than one output, and its output space is 00690 * not complete (i.e. not all output minterms are present, so the outputs 00691 * are correlated), then declare the table a relation. 00692 */ 00693 if ((Tbl_TableReadNumInputs(table) == 0) 00694 && (Tbl_TableReadNumOutputs(table) > 1)) { 00695 if (!Tbl_TableTestIsOutputSpaceComplete(table, mddMgr)) { 00696 (void) fprintf(vis_stderr, "Table %s is a relation\n", nodeName); 00697 result = FALSE; 00698 } 00699 } 00700 00701 if (!buildMvfs) { 00702 newTable = Tbl_TableSoftDup(table); 00703 newOutIndex = outIndex; 00704 } 00705 else { 00706 Mvf_Function_t *outMvf; 00707 int offset; 00708 int numInputs = Tbl_TableReadNumInputs(table); 00709 array_t *varMap = array_alloc(int, numInputs); 00710 00711 outMvf = LocalMvfFunctionForTable(table, outIndex, mddMgr, 00712 varMap, &offset); 00713 /* 00714 * If the function is not a non-deterministic constant, or it has some 00715 * inputs, then check that it is deterministic. Always check that it is 00716 * completely specified. 00717 */ 00718 if ((numInputs > 0) 00719 || !Mvf_FunctionTestIsNonDeterministicConstant(outMvf)) { 00720 if (!Mvf_FunctionTestIsDeterministic(outMvf)) { 00721 (void) fprintf(vis_stderr, "Table %s is not deterministic\n", nodeName); 00722 result = FALSE; 00723 } 00724 } 00725 if (!Mvf_FunctionTestIsCompletelySpecified(outMvf)) { 00726 (void) fprintf(vis_stderr, "Table %s is not completely specified\n", nodeName); 00727 result = FALSE; 00728 } 00729 00730 /* 00731 * Build the reduced table for the output corresponding to outIndex. The 00732 * reduced table will have only one output column (column 0), and will have 00733 * only those input columns corresponding to the variables appearing in the 00734 * support of outMvf. 00735 */ 00736 newTable = Tbl_TableCreateTrueSupportTableForOutput(table, outMvf, mddMgr, 00737 offset, outIndex, 00738 varMap); 00739 newOutIndex = 0; 00740 array_free(varMap); 00741 Mvf_FunctionFree(outMvf); 00742 } 00743 00744 00745 /* 00746 * Declare the node with the reduced table. 00747 */ 00748 if (Tbl_TableTestIsNonDeterministicConstant(newTable, newOutIndex)) { 00749 Ntk_NodeDeclareAsPseudoInput(node, newTable, newOutIndex); 00750 } 00751 else { 00752 array_t *formalInputNameArray = TableCreateFormalInputNameArray(newTable, path); 00753 00754 /* Ntk_NodeDeclareAsCombinational will test for constants. */ 00755 Ntk_NodeDeclareAsCombinational(node, newTable, formalInputNameArray, newOutIndex); 00756 NameArrayFree(formalInputNameArray); 00757 } 00758 00759 return result; 00760 } 00761 00762 00775 static void 00776 NetworkDeclareIONodes( 00777 Ntk_Network_t *network, 00778 Hrc_Node_t *hrcNode) 00779 { 00780 st_generator *stGen; 00781 char *varName; 00782 Var_Variable_t *var; 00783 char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); 00784 char *separator = (char *) ((strcmp(path, "")) ? "." : ""); 00785 00786 Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) { 00787 if (Var_VariableTestIsPO(var) || Var_VariableTestIsPI(var)) { 00788 char *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var)); 00789 char *tmpName = Ntk_NetworkReadActualNameFromFormalName(network, fullVarName); 00790 00791 /* 00792 * If tmpName == NIL, this must be a PI/PO of the top most node in the hierarchy of 00793 * nodes. Hence, this is a true input/output of the hierarchy. 00794 */ 00795 if (tmpName == NIL(char)) { 00796 Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, fullVarName); 00797 if (Var_VariableTestIsPO(var)) { 00798 Ntk_NodeDeclareAsPrimaryOutput(node); 00799 } 00800 else { 00801 Ntk_NodeDeclareAsPrimaryInput(node); 00802 } 00803 } 00804 FREE(fullVarName); 00805 } 00806 } 00807 FREE(path); 00808 } 00809 00810 00822 static void 00823 NetworkDeclareLatches( 00824 Ntk_Network_t *network, 00825 Hrc_Node_t *hrcNode) 00826 { 00827 st_generator *stGen; 00828 char *name; 00829 Hrc_Latch_t *latch; 00830 char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); 00831 char *separator = (char *) ((strcmp(path, "")) ? "." : ""); 00832 00833 Hrc_NodeForEachLatch(hrcNode, stGen, name, latch) { 00834 char *nextStateName; 00835 Ntk_Node_t *nextStateNode; 00836 char *latchName = util_strcat3(path, separator, 00837 Var_VariableReadName(Hrc_LatchReadOutput(latch))); 00838 char *initName = util_strcat3(latchName, "$INIT", ""); 00839 char *dataName = util_strcat3(path, separator, 00840 Var_VariableReadName(Hrc_LatchReadInput(latch))); 00841 Ntk_Node_t *latchNode = Ntk_NetworkFindNodeByName(network, latchName); 00842 00843 FREE(latchName); 00844 Ntk_NodeDeclareAsLatch(latchNode, dataName, initName); 00845 FREE(initName); 00846 FREE(dataName); 00847 00848 /* 00849 * Create the corresponding shadow next state node for the latch. This holds 00850 * the next state variable. 00851 */ 00852 nextStateName = util_strcat3(Ntk_NodeReadName(latchNode), "$NS", ""); 00853 nextStateNode = Ntk_NodeCreateInNetwork(network, nextStateName, 00854 Hrc_LatchReadOutput(latch)); 00855 FREE(nextStateName); 00856 Ntk_NodeDeclareAsShadow(nextStateNode, latchNode); 00857 } 00858 FREE(path); 00859 } 00860 00861 00876 static void 00877 MddManagerResetIfNecessary( 00878 mdd_manager **mddMgr) 00879 { 00880 if (bdd_num_vars(*mddMgr) > MAX_NUMBER_BDD_VARS) { 00881 mdd_quit(*mddMgr); 00882 *mddMgr = mdd_init_empty(); 00883 bdd_dynamic_reordering(*mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT); 00884 } 00885 } 00886 00887 00900 static Mvf_Function_t * 00901 LocalMvfFunctionForTable( 00902 Tbl_Table_t *table, 00903 int outIndex, 00904 mdd_manager *mddMgr, 00905 array_t *varMap, 00906 int *offsetPtr 00907 ) 00908 { 00909 Mvf_Function_t *outMvf; 00910 Var_Variable_t *var; 00911 int colNum; 00912 int offset; 00913 int i; 00914 int numInputs = Tbl_TableReadNumInputs(table); 00915 array_t *faninMvfArray = array_alloc(Mvf_Function_t *, numInputs); 00916 array_t *mvarValues = array_alloc(int, numInputs); 00917 st_table *varTable = st_init_table(st_ptrcmp,st_ptrhash); 00918 00919 /* Create MDD variables for the table inputs. If there are more inputs 00920 * tied to the sameVar_Variable_t, create just one MDD variable. Record 00921 * the mapping from inputs to variable indices in varMap. 00922 */ 00923 Tbl_TableForEachInputVar(table, colNum, var) { 00924 int index; 00925 if (st_lookup_int(varTable,var,&index)) { 00926 array_insert_last(int, varMap, index); 00927 } else { 00928 index = array_n(mvarValues); 00929 array_insert_last(int, varMap, index); 00930 st_insert(varTable, var, (char *) (long) index); 00931 array_insert_last(int, mvarValues, Var_VariableReadNumValues(var)); 00932 } 00933 } 00934 st_free_table(varTable); 00935 00936 /* Restarting the manager is optional. The effect is to get rid of the 00937 * MDD variable information in the manager, without incurring the cost 00938 * of quitting and re-initializing the manager. */ 00939 mdd_restart(mddMgr); 00940 offset = array_n(mdd_ret_mvar_list(mddMgr)); /* number of existing mvars */ 00941 assert(offset == 0); 00942 mdd_create_variables(mddMgr, mvarValues, NIL(array_t), NIL(array_t)); 00943 array_free(mvarValues); 00944 00945 /* 00946 * Construct an MVF for each table input. The MVF for column i is the MVF 00947 * for MDD variable i. 00948 */ 00949 for (i = 0; i < numInputs; i++) { 00950 int index = array_fetch(int, varMap, i); 00951 Mvf_Function_t *faninMvf = Mvf_FunctionCreateFromVariable(mddMgr, (index + offset)); 00952 array_insert_last(Mvf_Function_t *, faninMvfArray, faninMvf); 00953 } 00954 00955 /* Compute the MVF of the output indexed by outIndex. */ 00956 outMvf = Tbl_TableBuildMvfFromFanins(table, outIndex, faninMvfArray, mddMgr); 00957 Mvf_FunctionArrayFree(faninMvfArray); 00958 00959 *offsetPtr = offset; 00960 return outMvf; 00961 00962 } /* LocalMvfFunctionForTable */