[14] | 1 | /**CFile*********************************************************************** |
---|
| 2 | |
---|
| 3 | FileName [ntkFlt.c] |
---|
| 4 | |
---|
| 5 | PackageName [ntk] |
---|
| 6 | |
---|
| 7 | Synopsis [Routines for creating a network from a hierarchy manager.] |
---|
| 8 | |
---|
| 9 | Author [Adnan Aziz, Tom Shiple] |
---|
| 10 | |
---|
| 11 | Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. |
---|
| 12 | All rights reserved. |
---|
| 13 | |
---|
| 14 | Permission is hereby granted, without written agreement and without license |
---|
| 15 | or royalty fees, to use, copy, modify, and distribute this software and its |
---|
| 16 | documentation for any purpose, provided that the above copyright notice and |
---|
| 17 | the following two paragraphs appear in all copies of this software. |
---|
| 18 | |
---|
| 19 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR |
---|
| 20 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
---|
| 21 | OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF |
---|
| 22 | CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
| 23 | |
---|
| 24 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
---|
| 25 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
---|
| 26 | FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN |
---|
| 27 | "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE |
---|
| 28 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] |
---|
| 29 | |
---|
| 30 | ******************************************************************************/ |
---|
| 31 | |
---|
| 32 | #include "ntkInt.h" |
---|
| 33 | |
---|
| 34 | static char rcsid[] UNUSED = "$Id: ntkFlt.c,v 1.13 2009/04/11 22:17:58 fabio Exp $"; |
---|
| 35 | |
---|
| 36 | /*---------------------------------------------------------------------------*/ |
---|
| 37 | /* Constant declarations */ |
---|
| 38 | /*---------------------------------------------------------------------------*/ |
---|
| 39 | #define MAX_NUMBER_BDD_VARS 500 |
---|
| 40 | |
---|
| 41 | |
---|
| 42 | /*---------------------------------------------------------------------------*/ |
---|
| 43 | /* Macro declarations */ |
---|
| 44 | /*---------------------------------------------------------------------------*/ |
---|
| 45 | |
---|
| 46 | |
---|
| 47 | /**AutomaticStart*************************************************************/ |
---|
| 48 | |
---|
| 49 | /*---------------------------------------------------------------------------*/ |
---|
| 50 | /* Static function prototypes */ |
---|
| 51 | /*---------------------------------------------------------------------------*/ |
---|
| 52 | |
---|
| 53 | static void NetworkBuildFormalToActualTableRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode); |
---|
| 54 | static void NetworkCreateNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode); |
---|
| 55 | static void NodeCreateAsNecessary(Ntk_Network_t *network, char *nodeName, Var_Variable_t *var); |
---|
| 56 | static boolean NetworkDeclareNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode, boolean buildMvfs, mdd_manager **mddMgr); |
---|
| 57 | static array_t * LocalArrayJoin(array_t *array1, array_t *array2); |
---|
| 58 | static array_t * TableCreateFormalInputNameArray(Tbl_Table_t *table, char *namePrefix); |
---|
| 59 | static void NameArrayFree(array_t *nameArray); |
---|
| 60 | static boolean NetworkAbstractNodes(Ntk_Network_t *network, lsList abstractedNames); |
---|
| 61 | static boolean NodeDeclareWithTable(Ntk_Node_t *node, Tbl_Table_t *table, int outIndex, char *path, boolean buildMvfs, mdd_manager *mddMgr); |
---|
| 62 | static void NetworkDeclareIONodes(Ntk_Network_t *network, Hrc_Node_t *hrcNode); |
---|
| 63 | static void NetworkDeclareLatches(Ntk_Network_t *network, Hrc_Node_t *hrcNode); |
---|
| 64 | static void MddManagerResetIfNecessary(mdd_manager **mddMgr); |
---|
| 65 | static Mvf_Function_t * LocalMvfFunctionForTable(Tbl_Table_t *table, int outIndex, mdd_manager *mddMgr, array_t *varMap, int *offset); |
---|
| 66 | |
---|
| 67 | /**AutomaticEnd***************************************************************/ |
---|
| 68 | |
---|
| 69 | |
---|
| 70 | /*---------------------------------------------------------------------------*/ |
---|
| 71 | /* Definition of exported functions */ |
---|
| 72 | /*---------------------------------------------------------------------------*/ |
---|
| 73 | |
---|
| 74 | /**Function******************************************************************** |
---|
| 75 | |
---|
| 76 | Synopsis [Builds a flat description of a subtree of hierarchy manager.] |
---|
| 77 | |
---|
| 78 | Description [Builds a flat description of a subtree of a hierarchy manager. |
---|
| 79 | The flattened names of variables are taken as those hierarchical names where |
---|
| 80 | the variables are defined. The names are relative to the "current" node |
---|
| 81 | of the hierarchy manager, which can be set by calling |
---|
| 82 | Hrc_ManagerSetCurrentNode() first. Nodes are created even for unused |
---|
| 83 | variables (i.e. variables that don't fanout to anything.)<p> |
---|
| 84 | |
---|
| 85 | AbstractedNames is a list of char*. If the list is not NULL, then this list |
---|
| 86 | is interpreted as a list of variables to abstract. If a given name in the |
---|
| 87 | list does not correspond to the hierarchical name of a node in the network, |
---|
| 88 | then NULL is returned, and an error message is written to error_string. |
---|
| 89 | Otherwise, a new primary input is created to drive the net identified by the |
---|
| 90 | variable name. See the documentation for the command flatten_hierarchy for |
---|
| 91 | more information.<p> |
---|
| 92 | |
---|
| 93 | The verification routines assume deterministic and completely specified |
---|
| 94 | tables. If a table is found that is locally non-deterministic or incompletely |
---|
| 95 | specified, then a message is written to vis_stderr, and a NIL network is |
---|
| 96 | returned (the non-deterministic test is not performed on non-deterministic |
---|
| 97 | constant tables). This test can be bypassed (in order to save time) by |
---|
| 98 | passing FALSE for buildMvfs. Note that this should be done with extreme |
---|
| 99 | caution, because bad tables could inadvertantly be allowed through and |
---|
| 100 | invalidate verification results obtained downstream.<p> |
---|
| 101 | |
---|
| 102 | Also, if a table has no inputs and more than 1 output, and its output space |
---|
| 103 | is not complete (i.e. the outputs are correlated), then the table is |
---|
| 104 | declared a "relation", and NIL is returned.] |
---|
| 105 | |
---|
| 106 | SideEffects [] |
---|
| 107 | |
---|
| 108 | Comment [Proceeds in 3 phases: 1) builds a map from formals to actuals, 2) |
---|
| 109 | adds a node for each actual (i.e. for each node that will appear in the |
---|
| 110 | network) and 3) sets the types (and tables, where appropriate) for each |
---|
| 111 | node.] |
---|
| 112 | |
---|
| 113 | SeeAlso [Ntk_NetworkAlloc NetworkBuildFormalToActualTableRecursively |
---|
| 114 | NetworkCreateNodesRecursively NetworkDeclareNodesRecursively] |
---|
| 115 | |
---|
| 116 | ******************************************************************************/ |
---|
| 117 | Ntk_Network_t * |
---|
| 118 | Ntk_HrcNodeConvertToNetwork( |
---|
| 119 | Hrc_Node_t *hrcNode, |
---|
| 120 | boolean buildMvfs, |
---|
| 121 | lsList abstractedNames) |
---|
| 122 | { |
---|
| 123 | mdd_manager *mddMgr; |
---|
| 124 | boolean status1 = TRUE; |
---|
| 125 | boolean status2 = TRUE; |
---|
| 126 | char *hrcNodeName = Hrc_NodeReadInstanceName(hrcNode); |
---|
| 127 | Ntk_Network_t *network = Ntk_NetworkAlloc(hrcNodeName); |
---|
| 128 | |
---|
| 129 | NetworkBuildFormalToActualTableRecursively(network, hrcNode); |
---|
| 130 | NetworkCreateNodesRecursively(network, hrcNode); |
---|
| 131 | |
---|
| 132 | /* |
---|
| 133 | * The MDD manager is for building temporary MDDs. For robustness, enable |
---|
| 134 | * reordering. |
---|
| 135 | */ |
---|
| 136 | mddMgr = mdd_init_empty(); |
---|
| 137 | bdd_dynamic_reordering(mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT); |
---|
| 138 | status1 = NetworkDeclareNodesRecursively(network, hrcNode, buildMvfs, &mddMgr); |
---|
| 139 | mdd_quit(mddMgr); |
---|
| 140 | |
---|
| 141 | if (abstractedNames != (lsList) NULL) { |
---|
| 142 | status2 = NetworkAbstractNodes(network, abstractedNames); |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | if (!(status1 && status2)) { |
---|
| 146 | Ntk_NetworkFree(network); |
---|
| 147 | return NIL(Ntk_Network_t); |
---|
| 148 | } |
---|
| 149 | else { |
---|
| 150 | return network; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | |
---|
| 155 | /*---------------------------------------------------------------------------*/ |
---|
| 156 | /* Definition of internal functions */ |
---|
| 157 | /*---------------------------------------------------------------------------*/ |
---|
| 158 | |
---|
| 159 | |
---|
| 160 | /*---------------------------------------------------------------------------*/ |
---|
| 161 | /* Definition of static functions */ |
---|
| 162 | /*---------------------------------------------------------------------------*/ |
---|
| 163 | |
---|
| 164 | |
---|
| 165 | /**Function******************************************************************** |
---|
| 166 | |
---|
| 167 | Synopsis [Creates mapping from formal names to actual names.] |
---|
| 168 | |
---|
| 169 | Description [Loads the formal-to-actual table of network. For each formal |
---|
| 170 | variable name in hrcNode, maps it to a unique actual variable name. The map |
---|
| 171 | is many-to-one. The rule is that a formal is resolved to the actual as high |
---|
| 172 | in the hierarchy as possible. Proceeds recursively by examining |
---|
| 173 | subcircuits. Note that only formals are in the domain of the map. Also, care |
---|
| 174 | has to be taken when looking at net in parent since they may also be |
---|
| 175 | formals.] |
---|
| 176 | |
---|
| 177 | SideEffects [] |
---|
| 178 | |
---|
| 179 | ******************************************************************************/ |
---|
| 180 | static void |
---|
| 181 | NetworkBuildFormalToActualTableRecursively( |
---|
| 182 | Ntk_Network_t *network, |
---|
| 183 | Hrc_Node_t *hrcNode) |
---|
| 184 | { |
---|
| 185 | st_generator *stGen; |
---|
| 186 | char *childName; |
---|
| 187 | Hrc_Node_t *childHrcNode; |
---|
| 188 | |
---|
| 189 | /* |
---|
| 190 | * For each child of the current hnode, process its I/O variables, and |
---|
| 191 | * then recurse on its children. |
---|
| 192 | */ |
---|
| 193 | Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { |
---|
| 194 | |
---|
| 195 | int i; |
---|
| 196 | array_t *childFormalInputs = Hrc_NodeReadFormalInputs(childHrcNode); |
---|
| 197 | array_t *childFormalOutputs = Hrc_NodeReadFormalOutputs(childHrcNode); |
---|
| 198 | array_t *childFormalIoArray = LocalArrayJoin(childFormalInputs, childFormalOutputs); |
---|
| 199 | |
---|
| 200 | array_t *childActualInputs = Hrc_NodeReadActualInputs(childHrcNode); |
---|
| 201 | array_t *childActualOutputs = Hrc_NodeReadActualOutputs(childHrcNode); |
---|
| 202 | array_t *childActualIoArray = LocalArrayJoin(childActualInputs, childActualOutputs); |
---|
| 203 | |
---|
| 204 | |
---|
| 205 | /* |
---|
| 206 | * For each I/O variable, construct the appropriate hierarchical name for |
---|
| 207 | * the variable in childHrcNode (formalName) and the variable in the |
---|
| 208 | * hrcNode (actualName). If actualName already has a corresponding |
---|
| 209 | * actual, then use that, otherwise use actualName as is. Add |
---|
| 210 | * correspondence from formal (formalName) to actual (actualName). |
---|
| 211 | */ |
---|
| 212 | for(i = 0 ; i < array_n(childActualIoArray) ; i++) { |
---|
| 213 | Var_Variable_t *actualVar = array_fetch(Var_Variable_t *, childActualIoArray, i); |
---|
| 214 | Var_Variable_t *formalVar = array_fetch(Var_Variable_t *, childFormalIoArray, i); |
---|
| 215 | |
---|
| 216 | char *nodeName = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); |
---|
| 217 | /* Special case the situation where hrcNode is current node. */ |
---|
| 218 | char *actualName = (strcmp(nodeName, "")) |
---|
| 219 | ? util_strcat3(nodeName, ".", |
---|
| 220 | Var_VariableReadName(actualVar)) |
---|
| 221 | : util_strsav(Var_VariableReadName(actualVar)); |
---|
| 222 | |
---|
| 223 | char *childNodeName = Hrc_NodeFindHierarchicalName(childHrcNode, TRUE); |
---|
| 224 | char *formalName = util_strcat3(childNodeName, ".", |
---|
| 225 | Var_VariableReadName(formalVar)); |
---|
| 226 | |
---|
| 227 | /* |
---|
| 228 | * It is correct to call this function with actualName. We want to |
---|
| 229 | * check if actualVar is itself a formalVar one level up. |
---|
| 230 | */ |
---|
| 231 | char *tempName = Ntk_NetworkReadActualNameFromFormalName(network, actualName); |
---|
| 232 | |
---|
| 233 | FREE(nodeName); |
---|
| 234 | FREE(childNodeName); |
---|
| 235 | |
---|
| 236 | /* |
---|
| 237 | * (tempName != NIL) => this net is a formal in hrcNode |
---|
| 238 | */ |
---|
| 239 | if (tempName != NIL(char)) { |
---|
| 240 | FREE(actualName); |
---|
| 241 | actualName = tempName; |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | /* |
---|
| 245 | * Ntk_NetworkInsertFormalNameToActualName makes copies of the strings |
---|
| 246 | */ |
---|
| 247 | Ntk_NetworkInsertFormalNameToActualName(network, formalName, actualName); |
---|
| 248 | |
---|
| 249 | if (tempName == NIL(char)) { |
---|
| 250 | FREE(actualName); |
---|
| 251 | } |
---|
| 252 | FREE(formalName); |
---|
| 253 | } |
---|
| 254 | array_free(childFormalIoArray); |
---|
| 255 | array_free(childActualIoArray); |
---|
| 256 | |
---|
| 257 | /* |
---|
| 258 | * Recurse. |
---|
| 259 | */ |
---|
| 260 | NetworkBuildFormalToActualTableRecursively(network, childHrcNode); |
---|
| 261 | } |
---|
| 262 | } |
---|
| 263 | |
---|
| 264 | |
---|
| 265 | /**Function******************************************************************** |
---|
| 266 | |
---|
| 267 | Synopsis [Creates placeholders for all the nodes in the network.] |
---|
| 268 | |
---|
| 269 | Description [Working top-down, creates placeholders for all the nodes in the |
---|
| 270 | network. After this function is executed, each node will have a name and |
---|
| 271 | Var_Variable_t, but nothing else. Note that nodes are created for reset |
---|
| 272 | logic; they are given the name of their corresponding latch, suffixed by |
---|
| 273 | $INIT.] |
---|
| 274 | |
---|
| 275 | SideEffects [] |
---|
| 276 | |
---|
| 277 | SeeAlso [NodeCreateAsNecessary] |
---|
| 278 | |
---|
| 279 | ******************************************************************************/ |
---|
| 280 | static void |
---|
| 281 | NetworkCreateNodesRecursively( |
---|
| 282 | Ntk_Network_t *network, |
---|
| 283 | Hrc_Node_t *hrcNode) |
---|
| 284 | { |
---|
| 285 | st_generator *stGen; |
---|
| 286 | Var_Variable_t *var; |
---|
| 287 | Hrc_Latch_t *latch; |
---|
| 288 | char *varName; |
---|
| 289 | char *latchName; |
---|
| 290 | char *childName; |
---|
| 291 | Hrc_Node_t *childHrcNode; |
---|
| 292 | char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); |
---|
| 293 | char *separator = (char *) ((strcmp(path, "")) ? "." : ""); |
---|
| 294 | |
---|
| 295 | /* |
---|
| 296 | * The separator is used to handle the special case when hrcNode is the |
---|
| 297 | * current node in the hierarchy. If it is, we don't want a "." before the |
---|
| 298 | * variable names. |
---|
| 299 | */ |
---|
| 300 | |
---|
| 301 | Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) { |
---|
| 302 | char *nodeName = util_strcat3(path, separator, varName); |
---|
| 303 | NodeCreateAsNecessary(network, nodeName, var); |
---|
| 304 | FREE(nodeName); |
---|
| 305 | } |
---|
| 306 | |
---|
| 307 | /* |
---|
| 308 | * Variable for reset is the same as for present state. Hence, iterating |
---|
| 309 | * through the list of variables gets us just the present state. Therefore, |
---|
| 310 | * we need to special case the reset (or init) nodes. |
---|
| 311 | */ |
---|
| 312 | Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) { |
---|
| 313 | char *partialNodeName = util_strcat3(path, separator, latchName); |
---|
| 314 | char *nodeName = util_strcat3(partialNodeName, "$INIT", ""); |
---|
| 315 | |
---|
| 316 | FREE(partialNodeName); |
---|
| 317 | NodeCreateAsNecessary(network, nodeName, Hrc_LatchReadOutput(latch)); |
---|
| 318 | FREE(nodeName); |
---|
| 319 | } |
---|
| 320 | FREE(path); |
---|
| 321 | |
---|
| 322 | /* Recurse. */ |
---|
| 323 | Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { |
---|
| 324 | NetworkCreateNodesRecursively(network, childHrcNode); |
---|
| 325 | } |
---|
| 326 | } |
---|
| 327 | |
---|
| 328 | |
---|
| 329 | /**Function******************************************************************** |
---|
| 330 | |
---|
| 331 | Synopsis [Creates a node with a given name, if one doesn't already exist.] |
---|
| 332 | |
---|
| 333 | Description [If a node with nodeName already exists in the network, then |
---|
| 334 | does nothing. Otherwise, creates a new node in the network with nodeName |
---|
| 335 | and variable.] |
---|
| 336 | |
---|
| 337 | SideEffects [] |
---|
| 338 | |
---|
| 339 | ******************************************************************************/ |
---|
| 340 | static void |
---|
| 341 | NodeCreateAsNecessary( |
---|
| 342 | Ntk_Network_t *network, |
---|
| 343 | char *nodeName, |
---|
| 344 | Var_Variable_t *var) |
---|
| 345 | { |
---|
| 346 | if (Ntk_NetworkFindNodeByName(network, nodeName)) { |
---|
| 347 | return; |
---|
| 348 | } |
---|
| 349 | |
---|
| 350 | (void) Ntk_NodeCreateInNetwork(network, nodeName, var); |
---|
| 351 | } |
---|
| 352 | |
---|
| 353 | |
---|
| 354 | /**Function******************************************************************** |
---|
| 355 | |
---|
| 356 | Synopsis [Add functionality to the Ntk_Node_t's for this Hrc_Node_t.] |
---|
| 357 | |
---|
| 358 | Description [Add functionality to the Ntk_Node_t's for this Hrc_Node_t. |
---|
| 359 | Proceeds in 3 stages: 1) sets PI's and PO's; this is achieved by looking at |
---|
| 360 | PI/POs which are not formals, 2) adds tables to combinational logic, taking |
---|
| 361 | care to get the non-deterministic/deterministic constants right, 3) iterates |
---|
| 362 | over latches, adding type latch to nodes which have a name correspoding to |
---|
| 363 | this latch's ps name, and declaring the initialization logic for the |
---|
| 364 | latch.<p> |
---|
| 365 | |
---|
| 366 | If a table is found that is non-deterministic or incompletely specified, |
---|
| 367 | then a message is written to vis_stderr, and FALSE is returned (the |
---|
| 368 | non-deterministic test is not performed on non-deterministic constant |
---|
| 369 | tables). Also, if a table has no inputs and more than 1 output and its |
---|
| 370 | output space is not complete, then it's declared a "relation", and FALSE is |
---|
| 371 | returned. However, even if FALSE is returned, the nodes are still |
---|
| 372 | declared.<p> |
---|
| 373 | |
---|
| 374 | The non-deterministic or incompletely specified tests can be bypassed by |
---|
| 375 | passing FALSE for buildMvfs. See Ntk_HrcNodeConvertToNetwork for more info.] |
---|
| 376 | |
---|
| 377 | SideEffects [] |
---|
| 378 | |
---|
| 379 | ******************************************************************************/ |
---|
| 380 | static boolean |
---|
| 381 | NetworkDeclareNodesRecursively( |
---|
| 382 | Ntk_Network_t *network, |
---|
| 383 | Hrc_Node_t *hrcNode, |
---|
| 384 | boolean buildMvfs, |
---|
| 385 | mdd_manager **mddMgr) |
---|
| 386 | { |
---|
| 387 | int i; |
---|
| 388 | st_generator *stGen; |
---|
| 389 | char *latchName; |
---|
| 390 | Var_Variable_t *var; |
---|
| 391 | Hrc_Latch_t *latch; |
---|
| 392 | Tbl_Table_t *table; |
---|
| 393 | char *childName; |
---|
| 394 | Hrc_Node_t *childHrcNode; |
---|
| 395 | boolean result = TRUE; |
---|
| 396 | char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); |
---|
| 397 | char *separator = (char *) ((strcmp(path, "")) ? "." : ""); |
---|
| 398 | |
---|
| 399 | /* |
---|
| 400 | * First declare the network's PI/PO nodes. |
---|
| 401 | */ |
---|
| 402 | NetworkDeclareIONodes(network, hrcNode); |
---|
| 403 | |
---|
| 404 | /* |
---|
| 405 | * Next, declare those nodes whose function is represented by a table. Note |
---|
| 406 | * that his iterator does not pick up those tables that define the |
---|
| 407 | * initialization logic of latches. |
---|
| 408 | */ |
---|
| 409 | Hrc_NodeForEachNameTable(hrcNode, i, table) { |
---|
| 410 | int index; |
---|
| 411 | Tbl_TableForEachOutputVar(table, index, var) { |
---|
| 412 | boolean status; |
---|
| 413 | char *fullVarName = util_strcat3(path, separator, |
---|
| 414 | Var_VariableReadName(var)); |
---|
| 415 | Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, fullVarName); |
---|
| 416 | |
---|
| 417 | FREE(fullVarName); |
---|
| 418 | status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr); |
---|
| 419 | if (!status) { |
---|
| 420 | result = FALSE; |
---|
| 421 | } |
---|
| 422 | MddManagerResetIfNecessary(mddMgr); |
---|
| 423 | } |
---|
| 424 | } |
---|
| 425 | |
---|
| 426 | /* |
---|
| 427 | * Declare each latch and its corresponding next state shadow node. |
---|
| 428 | */ |
---|
| 429 | NetworkDeclareLatches(network, hrcNode); |
---|
| 430 | |
---|
| 431 | /* |
---|
| 432 | * Declare the "initial" node corresponding to each latch. |
---|
| 433 | */ |
---|
| 434 | Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) { |
---|
| 435 | int index; |
---|
| 436 | |
---|
| 437 | table = Hrc_LatchReadResetTable(latch); |
---|
| 438 | |
---|
| 439 | /* |
---|
| 440 | * There is only one output variable (the 0th output) for any table |
---|
| 441 | * defining the initial function of a latch, but we use an iterator to get |
---|
| 442 | * the variable for convenience. |
---|
| 443 | */ |
---|
| 444 | Tbl_TableForEachOutputVar(table, index, var) { |
---|
| 445 | boolean status; |
---|
| 446 | char *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var)); |
---|
| 447 | char *initName = util_strcat3(fullVarName, "$INIT", ""); |
---|
| 448 | Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, initName); |
---|
| 449 | |
---|
| 450 | /* |
---|
| 451 | * Since the output of this table corresponds to a latch PS, can get name |
---|
| 452 | * of the initial node by attaching $INIT. |
---|
| 453 | */ |
---|
| 454 | FREE(fullVarName); |
---|
| 455 | FREE(initName); |
---|
| 456 | |
---|
| 457 | status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr); |
---|
| 458 | if (!status) { |
---|
| 459 | result = FALSE; |
---|
| 460 | } |
---|
| 461 | MddManagerResetIfNecessary(mddMgr); |
---|
| 462 | } |
---|
| 463 | } |
---|
| 464 | FREE(path); |
---|
| 465 | |
---|
| 466 | /* Recurse. */ |
---|
| 467 | Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) { |
---|
| 468 | boolean status = NetworkDeclareNodesRecursively(network, childHrcNode, |
---|
| 469 | buildMvfs, mddMgr); |
---|
| 470 | if (!status) { |
---|
| 471 | result = FALSE; |
---|
| 472 | } |
---|
| 473 | } |
---|
| 474 | |
---|
| 475 | return result; |
---|
| 476 | } |
---|
| 477 | |
---|
| 478 | |
---|
| 479 | /**Function******************************************************************** |
---|
| 480 | |
---|
| 481 | Synopsis [Creates a new array consisting of array1 and array2.] |
---|
| 482 | |
---|
| 483 | Description [Returns a new array which consists of the elements of array 1 |
---|
| 484 | followed by the elements of array2.] |
---|
| 485 | |
---|
| 486 | Comment [It is suspected that the array_join from the array package is |
---|
| 487 | buggy when one of the arrays has 0 length. Hence, we defined our own.] |
---|
| 488 | |
---|
| 489 | SideEffects [] |
---|
| 490 | |
---|
| 491 | ******************************************************************************/ |
---|
| 492 | static array_t * |
---|
| 493 | LocalArrayJoin( |
---|
| 494 | array_t *array1, |
---|
| 495 | array_t *array2) |
---|
| 496 | { |
---|
| 497 | if (array_n(array1) == 0) { |
---|
| 498 | return (array_dup(array2)); |
---|
| 499 | } |
---|
| 500 | else if (array_n(array2) == 0) { |
---|
| 501 | return (array_dup(array1)); |
---|
| 502 | } |
---|
| 503 | else { |
---|
| 504 | return (array_join(array1, array2)); |
---|
| 505 | } |
---|
| 506 | } |
---|
| 507 | |
---|
| 508 | |
---|
| 509 | /**Function******************************************************************** |
---|
| 510 | |
---|
| 511 | Synopsis [Creates an array of table input names.] |
---|
| 512 | |
---|
| 513 | Description [Creates an array of table input names. For the ith input of |
---|
| 514 | table, the string "namePrefix.variableName_i" is placed in the ith position |
---|
| 515 | of the returned array, where variableName_i is the name of the variable |
---|
| 516 | corresponding to the ith input. (If namePrefix is "", then just |
---|
| 517 | "variableName_i" is used.) It is the responsiblity of the caller to free |
---|
| 518 | the strings in the returned array.] |
---|
| 519 | |
---|
| 520 | SideEffects [] |
---|
| 521 | |
---|
| 522 | SeeAlso [NameArrayFree] |
---|
| 523 | |
---|
| 524 | ******************************************************************************/ |
---|
| 525 | static array_t * |
---|
| 526 | TableCreateFormalInputNameArray( |
---|
| 527 | Tbl_Table_t *table, |
---|
| 528 | char *namePrefix) |
---|
| 529 | { |
---|
| 530 | int index; |
---|
| 531 | array_t *nameArray; |
---|
| 532 | Var_Variable_t *var; |
---|
| 533 | char *separator = (char *) ((strcmp(namePrefix, "")) ? "." : ""); |
---|
| 534 | |
---|
| 535 | /* |
---|
| 536 | * Allocate an array of length equal to the number of inputs of the table. |
---|
| 537 | * Then, for each input, add the full path name of the input to the array. |
---|
| 538 | */ |
---|
| 539 | nameArray = array_alloc(char *, Tbl_TableReadNumInputs(table)); |
---|
| 540 | Tbl_TableForEachInputVar(table, index, var) { |
---|
| 541 | char *inputFullName = util_strcat3(namePrefix, separator, Var_VariableReadName(var)); |
---|
| 542 | array_insert(char *, nameArray, index, inputFullName); |
---|
| 543 | } |
---|
| 544 | |
---|
| 545 | return (nameArray); |
---|
| 546 | } |
---|
| 547 | |
---|
| 548 | |
---|
| 549 | /**Function******************************************************************** |
---|
| 550 | |
---|
| 551 | Synopsis [Frees the strings in an array, and frees the array itself.] |
---|
| 552 | |
---|
| 553 | SideEffects [] |
---|
| 554 | |
---|
| 555 | SeeAlso [TableCreateFormalInputNameArray] |
---|
| 556 | |
---|
| 557 | ******************************************************************************/ |
---|
| 558 | static void |
---|
| 559 | NameArrayFree( |
---|
| 560 | array_t *nameArray) |
---|
| 561 | { |
---|
| 562 | int i; |
---|
| 563 | |
---|
| 564 | for (i = 0; i < array_n(nameArray); i++) { |
---|
| 565 | char *name = array_fetch(char *, nameArray, i); |
---|
| 566 | FREE(name); |
---|
| 567 | } |
---|
| 568 | array_free(nameArray); |
---|
| 569 | } |
---|
| 570 | |
---|
| 571 | /**Function******************************************************************** |
---|
| 572 | |
---|
| 573 | Synopsis [Abstract each node named in abstractedNames.] |
---|
| 574 | |
---|
| 575 | Description [Abstract each node named in abstractedNames. A node x is |
---|
| 576 | abstracted by creating a single new primary input node, with the name x$ABS |
---|
| 577 | and with the same variable as x, which will fanout to every node the |
---|
| 578 | original node fanned out to. The old node will continue to exists as before |
---|
| 579 | but will have no fanouts after abstraction; it can still be referred to in |
---|
| 580 | CTL formulas, etc.] |
---|
| 581 | |
---|
| 582 | SideEffects [] |
---|
| 583 | |
---|
| 584 | ******************************************************************************/ |
---|
| 585 | static boolean |
---|
| 586 | NetworkAbstractNodes( |
---|
| 587 | Ntk_Network_t *network, |
---|
| 588 | lsList abstractedNames) |
---|
| 589 | { |
---|
| 590 | char *name; |
---|
| 591 | lsGen gen; |
---|
| 592 | |
---|
| 593 | /* |
---|
| 594 | * For each abstracted name, cut the corresponding net, and introduce a new |
---|
| 595 | * node. |
---|
| 596 | */ |
---|
| 597 | lsForEachItem(abstractedNames, gen, name) { |
---|
| 598 | Var_Variable_t *var; |
---|
| 599 | Ntk_Node_t *abstractNode; |
---|
| 600 | array_t *abstractNodeFanouts; |
---|
| 601 | int i; |
---|
| 602 | Ntk_Node_t *fanout; |
---|
| 603 | char *abstractNodeName; |
---|
| 604 | Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, name); |
---|
| 605 | |
---|
| 606 | /* Make sure the name corresponds to a node in the network. */ |
---|
| 607 | if (node == NIL(Ntk_Node_t)) { |
---|
| 608 | error_append("Could not find node corresponding to name: "); |
---|
| 609 | error_append(name); |
---|
| 610 | error_append("\n"); |
---|
| 611 | return FALSE; |
---|
| 612 | } |
---|
| 613 | |
---|
| 614 | /* Create the new node in the network as a primary input. */ |
---|
| 615 | abstractNodeName = util_strcat3(name, "$ABS", ""); |
---|
| 616 | var = Ntk_NodeReadVariable(node); |
---|
| 617 | abstractNode = Ntk_NodeCreateInNetwork(network, abstractNodeName, var); |
---|
| 618 | FREE(abstractNodeName); |
---|
| 619 | Ntk_NodeDeclareAsPrimaryInput(abstractNode); |
---|
| 620 | |
---|
| 621 | /* |
---|
| 622 | * For each fanout y of the node x being abstracted, replace x in y's |
---|
| 623 | * fanin list by the new node, and add y to the fanout list of the new |
---|
| 624 | * node. |
---|
| 625 | */ |
---|
| 626 | abstractNodeFanouts = Ntk_NodeReadFanouts(abstractNode); |
---|
| 627 | Ntk_NodeForEachFanout(node, i, fanout) { |
---|
| 628 | int index = Ntk_NodeReadFaninIndex(fanout, node); |
---|
| 629 | array_t *fanoutFanins = Ntk_NodeReadFanins(fanout); |
---|
| 630 | |
---|
| 631 | array_insert(Ntk_Node_t *, fanoutFanins, index, abstractNode); |
---|
| 632 | array_insert_last(Ntk_Node_t *, abstractNodeFanouts, fanout); |
---|
| 633 | } |
---|
| 634 | |
---|
| 635 | /* |
---|
| 636 | * Replace the fanout array of the node being abstracted with an empty |
---|
| 637 | * array. |
---|
| 638 | */ |
---|
| 639 | array_free(node->fanouts); |
---|
| 640 | node->fanouts = array_alloc(Ntk_Node_t *, 0); |
---|
| 641 | } |
---|
| 642 | |
---|
| 643 | return TRUE; |
---|
| 644 | } |
---|
| 645 | |
---|
| 646 | |
---|
| 647 | /**Function******************************************************************** |
---|
| 648 | |
---|
| 649 | Synopsis [Declare a node with a table, and run some tests.] |
---|
| 650 | |
---|
| 651 | Description [Declare a node with a table, and run some tests. Creates the |
---|
| 652 | MVF for the output of table denoted by outIndex, in terms of the table |
---|
| 653 | inputs (new MDD variables are created). This MVF is created within mddMgr, |
---|
| 654 | and freed at the end of the function. The MVF is checked to see if it |
---|
| 655 | represents nondeterministic or incompletely specified behavior. If it does, |
---|
| 656 | a message is written to vis_stderr, and FALSE is returned. Also, if a table |
---|
| 657 | has no inputs and more than 1 output and its output space is not complete, |
---|
| 658 | then it's declared a "relation", and FALSE is returned.<p> |
---|
| 659 | |
---|
| 660 | If the table passes these tests, then a reduced table is built for this |
---|
| 661 | table output, consisting of just that output and the input columns in the |
---|
| 662 | support of that output. The node is then declared as a "pseudo-input" if |
---|
| 663 | the table represents a nondeterministic constant, or a "combinational" node |
---|
| 664 | otherwise.<p> |
---|
| 665 | |
---|
| 666 | Building the MVF, performing the tests, and building the reduced table, is |
---|
| 667 | bypassed if the input buildMvfs is FALSE. Note that this should be done with |
---|
| 668 | extreme caution, because bad tables could inadvertantly be allowed through |
---|
| 669 | and invalidate verification results obtained downstream.] |
---|
| 670 | |
---|
| 671 | SideEffects [] |
---|
| 672 | |
---|
| 673 | ******************************************************************************/ |
---|
| 674 | static boolean |
---|
| 675 | NodeDeclareWithTable( |
---|
| 676 | Ntk_Node_t *node, |
---|
| 677 | Tbl_Table_t *table, |
---|
| 678 | int outIndex, |
---|
| 679 | char *path, |
---|
| 680 | boolean buildMvfs, |
---|
| 681 | mdd_manager *mddMgr) |
---|
| 682 | { |
---|
| 683 | Tbl_Table_t *newTable; |
---|
| 684 | int newOutIndex; |
---|
| 685 | boolean result = TRUE; |
---|
| 686 | char *nodeName = Ntk_NodeReadName(node); |
---|
| 687 | |
---|
| 688 | /* |
---|
| 689 | * If table has no inputs and more than one output, and its output space is |
---|
| 690 | * not complete (i.e. not all output minterms are present, so the outputs |
---|
| 691 | * are correlated), then declare the table a relation. |
---|
| 692 | */ |
---|
| 693 | if ((Tbl_TableReadNumInputs(table) == 0) |
---|
| 694 | && (Tbl_TableReadNumOutputs(table) > 1)) { |
---|
| 695 | if (!Tbl_TableTestIsOutputSpaceComplete(table, mddMgr)) { |
---|
| 696 | (void) fprintf(vis_stderr, "Table %s is a relation\n", nodeName); |
---|
| 697 | result = FALSE; |
---|
| 698 | } |
---|
| 699 | } |
---|
| 700 | |
---|
| 701 | if (!buildMvfs) { |
---|
| 702 | newTable = Tbl_TableSoftDup(table); |
---|
| 703 | newOutIndex = outIndex; |
---|
| 704 | } |
---|
| 705 | else { |
---|
| 706 | Mvf_Function_t *outMvf; |
---|
| 707 | int offset; |
---|
| 708 | int numInputs = Tbl_TableReadNumInputs(table); |
---|
| 709 | array_t *varMap = array_alloc(int, numInputs); |
---|
| 710 | |
---|
| 711 | outMvf = LocalMvfFunctionForTable(table, outIndex, mddMgr, |
---|
| 712 | varMap, &offset); |
---|
| 713 | /* |
---|
| 714 | * If the function is not a non-deterministic constant, or it has some |
---|
| 715 | * inputs, then check that it is deterministic. Always check that it is |
---|
| 716 | * completely specified. |
---|
| 717 | */ |
---|
| 718 | if ((numInputs > 0) |
---|
| 719 | || !Mvf_FunctionTestIsNonDeterministicConstant(outMvf)) { |
---|
| 720 | if (!Mvf_FunctionTestIsDeterministic(outMvf)) { |
---|
| 721 | (void) fprintf(vis_stderr, "Table %s is not deterministic\n", nodeName); |
---|
| 722 | result = FALSE; |
---|
| 723 | } |
---|
| 724 | } |
---|
| 725 | if (!Mvf_FunctionTestIsCompletelySpecified(outMvf)) { |
---|
| 726 | (void) fprintf(vis_stderr, "Table %s is not completely specified\n", nodeName); |
---|
| 727 | result = FALSE; |
---|
| 728 | } |
---|
| 729 | |
---|
| 730 | /* |
---|
| 731 | * Build the reduced table for the output corresponding to outIndex. The |
---|
| 732 | * reduced table will have only one output column (column 0), and will have |
---|
| 733 | * only those input columns corresponding to the variables appearing in the |
---|
| 734 | * support of outMvf. |
---|
| 735 | */ |
---|
| 736 | newTable = Tbl_TableCreateTrueSupportTableForOutput(table, outMvf, mddMgr, |
---|
| 737 | offset, outIndex, |
---|
| 738 | varMap); |
---|
| 739 | newOutIndex = 0; |
---|
| 740 | array_free(varMap); |
---|
| 741 | Mvf_FunctionFree(outMvf); |
---|
| 742 | } |
---|
| 743 | |
---|
| 744 | |
---|
| 745 | /* |
---|
| 746 | * Declare the node with the reduced table. |
---|
| 747 | */ |
---|
| 748 | if (Tbl_TableTestIsNonDeterministicConstant(newTable, newOutIndex)) { |
---|
| 749 | Ntk_NodeDeclareAsPseudoInput(node, newTable, newOutIndex); |
---|
| 750 | } |
---|
| 751 | else { |
---|
| 752 | array_t *formalInputNameArray = TableCreateFormalInputNameArray(newTable, path); |
---|
| 753 | |
---|
| 754 | /* Ntk_NodeDeclareAsCombinational will test for constants. */ |
---|
| 755 | Ntk_NodeDeclareAsCombinational(node, newTable, formalInputNameArray, newOutIndex); |
---|
| 756 | NameArrayFree(formalInputNameArray); |
---|
| 757 | } |
---|
| 758 | |
---|
| 759 | return result; |
---|
| 760 | } |
---|
| 761 | |
---|
| 762 | |
---|
| 763 | /**Function******************************************************************** |
---|
| 764 | |
---|
| 765 | Synopsis [Declares the primary inputs and outputs of the network.] |
---|
| 766 | |
---|
| 767 | Description [Declares the primary inputs and outputs of the network. Does |
---|
| 768 | this by iterating over the variables of the hrcNode. Any variable it finds |
---|
| 769 | that doesn't have a corresponding actual name in the network's corresponding |
---|
| 770 | formal-to-actual table is considered a primary IO.] |
---|
| 771 | |
---|
| 772 | SideEffects [] |
---|
| 773 | |
---|
| 774 | ******************************************************************************/ |
---|
| 775 | static void |
---|
| 776 | NetworkDeclareIONodes( |
---|
| 777 | Ntk_Network_t *network, |
---|
| 778 | Hrc_Node_t *hrcNode) |
---|
| 779 | { |
---|
| 780 | st_generator *stGen; |
---|
| 781 | char *varName; |
---|
| 782 | Var_Variable_t *var; |
---|
| 783 | char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); |
---|
| 784 | char *separator = (char *) ((strcmp(path, "")) ? "." : ""); |
---|
| 785 | |
---|
| 786 | Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) { |
---|
| 787 | if (Var_VariableTestIsPO(var) || Var_VariableTestIsPI(var)) { |
---|
| 788 | char *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var)); |
---|
| 789 | char *tmpName = Ntk_NetworkReadActualNameFromFormalName(network, fullVarName); |
---|
| 790 | |
---|
| 791 | /* |
---|
| 792 | * If tmpName == NIL, this must be a PI/PO of the top most node in the hierarchy of |
---|
| 793 | * nodes. Hence, this is a true input/output of the hierarchy. |
---|
| 794 | */ |
---|
| 795 | if (tmpName == NIL(char)) { |
---|
| 796 | Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, fullVarName); |
---|
| 797 | if (Var_VariableTestIsPO(var)) { |
---|
| 798 | Ntk_NodeDeclareAsPrimaryOutput(node); |
---|
| 799 | } |
---|
| 800 | else { |
---|
| 801 | Ntk_NodeDeclareAsPrimaryInput(node); |
---|
| 802 | } |
---|
| 803 | } |
---|
| 804 | FREE(fullVarName); |
---|
| 805 | } |
---|
| 806 | } |
---|
| 807 | FREE(path); |
---|
| 808 | } |
---|
| 809 | |
---|
| 810 | |
---|
| 811 | /**Function******************************************************************** |
---|
| 812 | |
---|
| 813 | Synopsis [Declares the latches of the network.] |
---|
| 814 | |
---|
| 815 | Description [Declares the latches of the network. Does this by iterating |
---|
| 816 | over the latches of the hrcNode. For each latch, also creates and declares |
---|
| 817 | a corresponding next state shadow node.] |
---|
| 818 | |
---|
| 819 | SideEffects [] |
---|
| 820 | |
---|
| 821 | ******************************************************************************/ |
---|
| 822 | static void |
---|
| 823 | NetworkDeclareLatches( |
---|
| 824 | Ntk_Network_t *network, |
---|
| 825 | Hrc_Node_t *hrcNode) |
---|
| 826 | { |
---|
| 827 | st_generator *stGen; |
---|
| 828 | char *name; |
---|
| 829 | Hrc_Latch_t *latch; |
---|
| 830 | char *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE); |
---|
| 831 | char *separator = (char *) ((strcmp(path, "")) ? "." : ""); |
---|
| 832 | |
---|
| 833 | Hrc_NodeForEachLatch(hrcNode, stGen, name, latch) { |
---|
| 834 | char *nextStateName; |
---|
| 835 | Ntk_Node_t *nextStateNode; |
---|
| 836 | char *latchName = util_strcat3(path, separator, |
---|
| 837 | Var_VariableReadName(Hrc_LatchReadOutput(latch))); |
---|
| 838 | char *initName = util_strcat3(latchName, "$INIT", ""); |
---|
| 839 | char *dataName = util_strcat3(path, separator, |
---|
| 840 | Var_VariableReadName(Hrc_LatchReadInput(latch))); |
---|
| 841 | Ntk_Node_t *latchNode = Ntk_NetworkFindNodeByName(network, latchName); |
---|
| 842 | |
---|
| 843 | FREE(latchName); |
---|
| 844 | Ntk_NodeDeclareAsLatch(latchNode, dataName, initName); |
---|
| 845 | FREE(initName); |
---|
| 846 | FREE(dataName); |
---|
| 847 | |
---|
| 848 | /* |
---|
| 849 | * Create the corresponding shadow next state node for the latch. This holds |
---|
| 850 | * the next state variable. |
---|
| 851 | */ |
---|
| 852 | nextStateName = util_strcat3(Ntk_NodeReadName(latchNode), "$NS", ""); |
---|
| 853 | nextStateNode = Ntk_NodeCreateInNetwork(network, nextStateName, |
---|
| 854 | Hrc_LatchReadOutput(latch)); |
---|
| 855 | FREE(nextStateName); |
---|
| 856 | Ntk_NodeDeclareAsShadow(nextStateNode, latchNode); |
---|
| 857 | } |
---|
| 858 | FREE(path); |
---|
| 859 | } |
---|
| 860 | |
---|
| 861 | |
---|
| 862 | /**Function******************************************************************** |
---|
| 863 | |
---|
| 864 | Synopsis [Potentially quits mddMgr and starts a new one.] |
---|
| 865 | |
---|
| 866 | Description [Quits mddMgr if the number of binary variables exceeds |
---|
| 867 | MAX_NUMBER_BDD_VARS, and starts a new manager with no variables. |
---|
| 868 | Initializing an empty MDD manager is costly in some BDD packages, so we want |
---|
| 869 | to avoid doing it often (say, once per table). On the other hand, we don't |
---|
| 870 | want the manager to have too many variables, because then reordering becomes |
---|
| 871 | expensive.] |
---|
| 872 | |
---|
| 873 | SideEffects [] |
---|
| 874 | |
---|
| 875 | ******************************************************************************/ |
---|
| 876 | static void |
---|
| 877 | MddManagerResetIfNecessary( |
---|
| 878 | mdd_manager **mddMgr) |
---|
| 879 | { |
---|
| 880 | if (bdd_num_vars(*mddMgr) > MAX_NUMBER_BDD_VARS) { |
---|
| 881 | mdd_quit(*mddMgr); |
---|
| 882 | *mddMgr = mdd_init_empty(); |
---|
| 883 | bdd_dynamic_reordering(*mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT); |
---|
| 884 | } |
---|
| 885 | } |
---|
| 886 | |
---|
| 887 | |
---|
| 888 | /**Function******************************************************************** |
---|
| 889 | |
---|
| 890 | Synopsis [Builds the MVF of a table in terms of local variables.] |
---|
| 891 | |
---|
| 892 | Description [Builds the MVF of a table in terms of local variables. Also |
---|
| 893 | computes the offset of the local variables in the MDD manager and builds |
---|
| 894 | a map from the input columns of the table to the MDD id's. The offset is |
---|
| 895 | always 0 if the MDD manager is restarted.] |
---|
| 896 | |
---|
| 897 | SideEffects [varMap and offsetPtr are returned as side effects] |
---|
| 898 | |
---|
| 899 | ******************************************************************************/ |
---|
| 900 | static Mvf_Function_t * |
---|
| 901 | LocalMvfFunctionForTable( |
---|
| 902 | Tbl_Table_t *table, |
---|
| 903 | int outIndex, |
---|
| 904 | mdd_manager *mddMgr, |
---|
| 905 | array_t *varMap, |
---|
| 906 | int *offsetPtr |
---|
| 907 | ) |
---|
| 908 | { |
---|
| 909 | Mvf_Function_t *outMvf; |
---|
| 910 | Var_Variable_t *var; |
---|
| 911 | int colNum; |
---|
| 912 | int offset; |
---|
| 913 | int i; |
---|
| 914 | int numInputs = Tbl_TableReadNumInputs(table); |
---|
| 915 | array_t *faninMvfArray = array_alloc(Mvf_Function_t *, numInputs); |
---|
| 916 | array_t *mvarValues = array_alloc(int, numInputs); |
---|
| 917 | st_table *varTable = st_init_table(st_ptrcmp,st_ptrhash); |
---|
| 918 | |
---|
| 919 | /* Create MDD variables for the table inputs. If there are more inputs |
---|
| 920 | * tied to the sameVar_Variable_t, create just one MDD variable. Record |
---|
| 921 | * the mapping from inputs to variable indices in varMap. |
---|
| 922 | */ |
---|
| 923 | Tbl_TableForEachInputVar(table, colNum, var) { |
---|
| 924 | int index; |
---|
| 925 | if (st_lookup_int(varTable,var,&index)) { |
---|
| 926 | array_insert_last(int, varMap, index); |
---|
| 927 | } else { |
---|
| 928 | index = array_n(mvarValues); |
---|
| 929 | array_insert_last(int, varMap, index); |
---|
| 930 | st_insert(varTable, var, (char *) (long) index); |
---|
| 931 | array_insert_last(int, mvarValues, Var_VariableReadNumValues(var)); |
---|
| 932 | } |
---|
| 933 | } |
---|
| 934 | st_free_table(varTable); |
---|
| 935 | |
---|
| 936 | /* Restarting the manager is optional. The effect is to get rid of the |
---|
| 937 | * MDD variable information in the manager, without incurring the cost |
---|
| 938 | * of quitting and re-initializing the manager. */ |
---|
| 939 | mdd_restart(mddMgr); |
---|
| 940 | offset = array_n(mdd_ret_mvar_list(mddMgr)); /* number of existing mvars */ |
---|
| 941 | assert(offset == 0); |
---|
| 942 | mdd_create_variables(mddMgr, mvarValues, NIL(array_t), NIL(array_t)); |
---|
| 943 | array_free(mvarValues); |
---|
| 944 | |
---|
| 945 | /* |
---|
| 946 | * Construct an MVF for each table input. The MVF for column i is the MVF |
---|
| 947 | * for MDD variable i. |
---|
| 948 | */ |
---|
| 949 | for (i = 0; i < numInputs; i++) { |
---|
| 950 | int index = array_fetch(int, varMap, i); |
---|
| 951 | Mvf_Function_t *faninMvf = Mvf_FunctionCreateFromVariable(mddMgr, (index + offset)); |
---|
| 952 | array_insert_last(Mvf_Function_t *, faninMvfArray, faninMvf); |
---|
| 953 | } |
---|
| 954 | |
---|
| 955 | /* Compute the MVF of the output indexed by outIndex. */ |
---|
| 956 | outMvf = Tbl_TableBuildMvfFromFanins(table, outIndex, faninMvfArray, mddMgr); |
---|
| 957 | Mvf_FunctionArrayFree(faninMvfArray); |
---|
| 958 | |
---|
| 959 | *offsetPtr = offset; |
---|
| 960 | return outMvf; |
---|
| 961 | |
---|
| 962 | } /* LocalMvfFunctionForTable */ |
---|