/**CFile*********************************************************************** FileName [hrcMisc.c] PackageName [hrc] Synopsis [This file provides some miscellaneous functions.] SeeAlso [] Author [Shaz Qadeer] Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] ******************************************************************************/ #include "hrcInt.h" static char rcsid[] UNUSED = "$Id: hrcMisc.c,v 1.4 2005/04/27 00:10:58 fabio Exp $"; /*---------------------------------------------------------------------------*/ /* Constant declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Type declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Stucture declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Variable declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Macro declarations */ /*---------------------------------------------------------------------------*/ /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ static void NodeObtainComponentModels(Hrc_Node_t *node, st_table *models); /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Returns pointer to the node corresponding to a path name.] Description [The function returns a pointer to the node corresponding to a path name. If pathFlag is TRUE it is assumed that the name begins from the current node otherwise the name is assumed to begin from the root node. If the pathname is correct, the corresponding node is returned otherwise NULL is returned. Note that the pathname should start with instance name of the child of the current node or the root node as the case may be. The individual instance names are separated by ".".] SideEffects [] SeeAlso [] ******************************************************************************/ Hrc_Node_t * Hrc_ManagerFindNodeByPathName( Hrc_Manager_t *manager, char *path, boolean pathFlag) { int position, count; int i = 0; Hrc_Node_t *presentNode; char *name; /* Check whether the pathname begins from the root node or the current node and initialize presentNode accordingly. */ if(pathFlag == FALSE) { /* Hierarchy will be traversed beginning from root node. */ presentNode = manager->rootNode; } else { /* Hierarchy will be traversed beginning from current node. */ presentNode = manager->currentNode; } position = i; /* The name of a particular node in the pathname begins at position. position is updated every time presentNode is updated to a child from the parent. */ count = 0; while(path[i] != '\0') { if(path[i] == '.') { name = ALLOC(char, count+1); strncpy(name, path+position, count); name[count] = '\0'; if((presentNode = Hrc_NodeFindChildByName(presentNode, name)) == NIL(Hrc_Node_t)) { FREE(name); return NIL(Hrc_Node_t); } position += count + 1; count = 0; FREE(name); } else { count++; } i++; } name = ALLOC(char, count+1); strncpy(name, path+position, count); name[count] = '\0'; if((presentNode = Hrc_NodeFindChildByName(presentNode, name)) == NIL(Hrc_Node_t)) { FREE(name); return NIL(Hrc_Node_t); } FREE(name); return presentNode; } /**Function******************************************************************** Synopsis [Returns pointer to the actual variable corresponding to a formal variable of a node.] Description [The function tracks a formal variable up in the hierarchy until that variable becomes an internal variable of a node. While traversing the hierarchy upwards it does not go beyond the specified reference node. If node is identical to reference node, formalVar is returned. If any error occurs a NULL pointer is returned] SideEffects [] SeeAlso [] ******************************************************************************/ Var_Variable_t * Hrc_VariableFindActualFromFormal( Hrc_Node_t *node, Var_Variable_t *formalVar, Hrc_Node_t *referenceNode) { int position = -1; int i; Var_Variable_t *var; Hrc_Node_t *presentNode; Var_Variable_t *presentVar; char *varName; if(node == referenceNode) { return formalVar; } else { presentNode = node; presentVar = formalVar; } /* A variable at position i in formalInputs corresponds to a varible at position i in actualInputs. The variables in actualInputs in a node are actually formal variables (could be I/O or internal) of the parent of the node. Given a formal variable and a node, search for the variable in formalInputs and formalOutputs. If it is not present in either then check if it is an internal variable of the node. If it is present, get the corresponding variable from actualInputs or actualOutputs as the case may be. Update presentVar to this variable and presentNode to the parent of the node. Repeat the process until presentVar is an internal variable of presentNode or presentNode becomes the same as referenceNode. */ while(presentNode != referenceNode) { Hrc_NodeForEachFormalInput(presentNode, i, var) { if(var == presentVar) { position = i; } } if(position != -1) { presentVar = array_fetch(Var_Variable_t *, presentNode->actualInputs, position); } else { Hrc_NodeForEachFormalOutput(presentNode, i, var) { if(var == presentVar) { position = i; } } if(position != -1) { presentVar = array_fetch(Var_Variable_t *, presentNode->actualOutputs, position); } else { varName = Var_VariableReadName(presentVar); if(st_is_member(presentNode->varTable, varName)) { return presentVar; } else { return NIL(Var_Variable_t); } } } presentNode = presentNode->parentNode; /* The following check is just to make sure that the function does not try to access the parent of the root node. */ if(presentNode == NIL(Hrc_Node_t )) { return NIL(Var_Variable_t); } position = -1; } return presentVar; } /**Function******************************************************************** Synopsis [Returns an array of models being used in the hierarchy below the current node.] SideEffects [] SeeAlso [] ******************************************************************************/ array_t * Hrc_ManagerObtainComponentModels( Hrc_Manager_t *manager) { st_generator *gen; char *modelName; char *dummy; Hrc_Model_t *model; st_table *modelTable = st_init_table(strcmp, st_strhash); array_t *modelArray = array_alloc(Hrc_Model_t *, 0); NodeObtainComponentModels(manager->currentNode, modelTable); st_foreach_item(modelTable, gen, &modelName, &dummy) { st_lookup(manager->modelTable, modelName, &model); array_insert_last(Hrc_Model_t *, modelArray, model); } st_free_table(modelTable); return modelArray; } /**Function******************************************************************** Synopsis [Returns the hierarchical name of a node.] Description [A pointer to a string containing the hierarchical name is returned. The user is responsible for freeing this string. If pathFlag is set to TRUE the name is found relative to the current node otherwise the name is found relative to the root node. The path name of root node relative to the root node and the current node relative to the current node is "". If there is any error NULL is returned. Note that for each level of hierarchy that is traversed there is an instance name and these are separated by ".".] SideEffects [] SeeAlso [Hrc_ManagerFindNodeByPathName()] ******************************************************************************/ char * Hrc_NodeFindHierarchicalName( Hrc_Node_t *node, boolean pathFlag) { Hrc_Manager_t *manager = Hrc_NodeReadManager(node); Hrc_Node_t *currentNode, *rootNode, *tempNode; char *name; char *parentName; char *temp; rootNode = Hrc_ManagerReadRootNode(manager); currentNode = Hrc_ManagerReadCurrentNode(manager); if(pathFlag == FALSE) { if(node == rootNode) { name = util_strsav(""); } else { tempNode = node; name = util_strsav(Hrc_NodeReadInstanceName(tempNode)); while((tempNode = Hrc_NodeReadParentNode(tempNode)) != rootNode) { parentName = util_strsav(Hrc_NodeReadInstanceName(tempNode)); temp = util_strcat3(parentName, ".", name); FREE(parentName); FREE(name); name = temp; } } } else { if(node == currentNode) { name = util_strsav(""); } else { tempNode = node; name = util_strsav(Hrc_NodeReadInstanceName(tempNode)); if(tempNode == rootNode) { /* return NULL. In this case, the function is being asked to find the pathname of root node relative to the current node, when the current node is not the root node */ FREE(name); return NIL(char); } while((tempNode = Hrc_NodeReadParentNode(tempNode)) != currentNode) { if(tempNode == rootNode) { FREE(name); return NIL(char); } parentName = util_strsav(Hrc_NodeReadInstanceName(tempNode)); temp = util_strcat3(parentName, ".", name); FREE(parentName); FREE(name); name = temp; } } } return name; } /**Function******************************************************************** Synopsis [Returns pointer to a hash table from global path name of a formal variable to actual variable] Description [The hash table returned is from the global path name of a formal variable to the global path name of its corresponding actual variable. While traversing up the hierarchy, the function will not go beyond rootNode.] SideEffects [None] SeeAlso [optional] ******************************************************************************/ /*st_table * Hrc_TableCreateFormalToActual( Hrc_Node_t *rootNode) { }*/ /**Function******************************************************************** Synopsis [Replaces a sub-tree in the hierarchy with a another tree.] Description [The function replaces a sub-tree in the hierarchy whose root is oldNode by another tree whose root node is specified by newNode. It is illegal for newNode to be NULL. If oldNode is NULL, the tree hanging from newNode is freed recursively and TRUE is returned. Otherwise, it is checked whether newNode is a part of the existing hierarchy. If it is, FALSE is returned and nothing is done. If it is not, oldNode is replaced by newNode in the hierarchy and TRUE is returned. To effect the replacement, the applInfoTable of newNode is freed and a copy of applInfoTable of oldNode is stored in its place. Then changeFn is called for each entry in the table. The hierarchy is traversed towards the root node starting from the parent of oldNode. At each step, a new model is created and registered with the hierarchy manager. The new model names are obtained by appending a '~' to the name of the model which was modified. Finally, oldNode is freed recursively.] SideEffects [The hierarchy tree is modified and new models are added.] SeeAlso [] ******************************************************************************/ boolean Hrc_TreeReplace( Hrc_Node_t *oldNode, Hrc_Node_t *newNode) { Hrc_Node_t *tempNode, *presentNode; char *newName, *instanceName; char *newInstanceName; int i, num, index; Hrc_Model_t *prevOldModel, *prevNewModel; Hrc_Model_t *oldModel, *newModel; Hrc_Model_t *calleeModel; Hrc_Subckt_t *subckt; st_table *varToDupVar; Tbl_Table_t *table, *dupTable; Var_Variable_t *var, *dupVar; char *name, *dupName; st_generator *gen; Hrc_Latch_t *latch, *dupLatch; array_t *newActualInputVars, *newActualOutputVars; char *key; ApplInfo_t *applInfo; /* It is illegal to pass NULL as newNode. */ assert(newNode != NIL(Hrc_Node_t)); if(oldNode == NIL(Hrc_Node_t)) { HrcNodeFreeRecursively(newNode); return TRUE; } if(Hrc_NodeTestIsInTree(newNode, oldNode->manager->rootNode)) { return FALSE; } /* free applInfo strutures all the way to the root since flattened networks get invalidated with this tree-replace. */ presentNode = oldNode; while(presentNode != NIL(Hrc_Node_t)) { st_foreach_item(presentNode->applInfoTable, gen, &key, &applInfo) { (*applInfo->freeFn)(applInfo->data); FREE(key); FREE(applInfo); } st_free_table(presentNode->applInfoTable); presentNode->applInfoTable = st_init_table(strcmp, st_strhash); presentNode = Hrc_NodeReadParentNode(presentNode); } /* If oldNode is the root node of the hierarchy, simply set the root node and current node of the hierarchy to newNode. */ if(oldNode->parentNode == NIL(Hrc_Node_t)) { Hrc_ManagerSetRootNode(oldNode->manager, newNode); Hrc_ManagerSetCurrentNode(oldNode->manager, newNode); } else { /* First, remove the connection between oldNode and its parent and establish connection between newNode and oldNode's parent. */ tempNode = HrcNodeDeleteChild(oldNode->parentNode, oldNode->instanceName); assert(oldNode == tempNode); FREE(newNode->instanceName); newNode->instanceName = util_strsav(oldNode->instanceName); newNode->parentNode = oldNode->parentNode; st_insert(newNode->parentNode->childTable, newNode->instanceName, (char *) newNode); newNode->actualInputs = array_dup(oldNode->actualInputs); newNode->actualOutputs = array_dup(oldNode->actualOutputs); /* Starting from the parent of oldNode (now the parent of newNode), go up the hierarchy and at each node generate a new model by modifying the model corresponding to the node appropriately. The new model name is obtained from the old one by appending a '~' to it. The model names in the nodes traversed have to be modified. The three variables newInstanceName, prevOldModel and prevNewModel keep information needed to generate new models by modifying already existing ones. */ newInstanceName = newNode->instanceName; presentNode = newNode->parentNode; st_lookup(presentNode->manager->modelTable, oldNode->modelName, &prevOldModel); st_lookup(presentNode->manager->modelTable, newNode->modelName, &prevNewModel); while(presentNode != NIL(Hrc_Node_t)) { oldModel = Hrc_ManagerFindModelByName(presentNode->manager, presentNode->modelName); newName = ALLOC(char, strlen(presentNode->modelName) + 2); strcpy(newName, presentNode->modelName); strcat(newName, "~"); FREE(presentNode->modelName); presentNode->modelName = newName; /* Allocate a new model and fill up its fields by copying and modifying appropriately the fields from the old model */ newModel = Hrc_ModelAlloc(presentNode->manager, presentNode->modelName); /* Fill in the entries of the master node of newModel. I couldn't use Hrc_NodeDup() to duplicate the master node of the oldModel here because that function does some other things too. All the variables of the masterNode of oldModel are duplicated. Note that masterNode and the nodes in the hierarchy corresponding to the model do not share variables. */ varToDupVar = st_init_table(st_ptrcmp, st_ptrhash); Hrc_NodeForEachVariable(oldModel->masterNode, gen, name, var) { dupVar = Var_VariableDup(var, newModel->masterNode); dupName = Var_VariableReadName(dupVar); st_insert(newModel->masterNode->varTable, dupName, dupVar); st_insert(varToDupVar, var, dupVar); } Hrc_NodeForEachFormalInput(oldModel->masterNode, i, var) { st_lookup(varToDupVar, var, &dupVar); array_insert_last(Var_Variable_t *, newModel->masterNode->formalInputs, dupVar); } Hrc_NodeForEachFormalOutput(oldModel->masterNode, i, var) { st_lookup(varToDupVar, var, &dupVar); array_insert_last(Var_Variable_t *, newModel->masterNode->formalOutputs, dupVar); } Hrc_NodeForEachNameTable(oldModel->masterNode, i, table) { dupTable = Tbl_TableSoftDup(table); Tbl_TableForEachInputVar(dupTable, index, var) { st_lookup(varToDupVar, var, &dupVar); Tbl_TableSubstituteVar(dupTable, var, dupVar); } Tbl_TableForEachOutputVar(dupTable, index, var) { st_lookup(varToDupVar, var, &dupVar); Tbl_TableSubstituteVar(dupTable, var, dupVar); } array_insert_last(Tbl_Table_t *, newModel->masterNode->nameTables, dupTable); } Hrc_NodeForEachLatch(oldModel->masterNode, gen, name, latch) { dupLatch = ALLOC(Hrc_Latch_t, 1); st_lookup(varToDupVar, latch->latchInput, &(dupLatch->latchInput)); st_lookup(varToDupVar, latch->latchOutput, &(dupLatch->latchOutput)); dupLatch->resetTable = Tbl_TableSoftDup(latch->resetTable); Tbl_TableForEachInputVar(dupLatch->resetTable, index, var) { st_lookup(varToDupVar, var, &dupVar); Tbl_TableSubstituteVar(dupLatch->resetTable, var, dupVar); } Tbl_TableForEachOutputVar(dupLatch->resetTable, index, var) { st_lookup(varToDupVar, var, &dupVar); Tbl_TableSubstituteVar(dupLatch->resetTable, var, dupVar); } dupLatch->undef = latch->undef; st_insert(newModel->masterNode->latchTable, Var_VariableReadName(dupLatch->latchOutput), dupLatch); } /* For each subckt entry in oldModel, add a corresponding entry to newModel except for the entry corresponding to the modified child of presentNode. This particular subckt is recognized by its instanceName. */ Hrc_ModelForEachSubckt(oldModel, gen, name, subckt) { if(!strcmp(subckt->instanceName, newInstanceName)) { calleeModel = prevNewModel; } else { calleeModel = subckt->model; } instanceName = subckt->instanceName; newActualInputVars = array_alloc(Var_Variable_t *, 0); num = array_n(subckt->actualInputVars); for(i =0; i < num; ++i) { var = array_fetch(Var_Variable_t *, subckt->actualInputVars, i); st_lookup(varToDupVar, var, &dupVar); array_insert_last(Var_Variable_t *, newActualInputVars, dupVar); } newActualOutputVars = array_alloc(Var_Variable_t *, 0); num = array_n(subckt->actualOutputVars); for(i =0; i < num; ++i) { var = array_fetch(Var_Variable_t *, subckt->actualOutputVars, i); st_lookup(varToDupVar, var, &dupVar); array_insert_last(Var_Variable_t *, newActualOutputVars, dupVar); } Hrc_ModelAddSubckt(newModel, calleeModel, instanceName, newActualInputVars, newActualOutputVars); } st_free_table(varToDupVar); newInstanceName = presentNode->instanceName; /* Right now, I am not modifying the instance names. */ prevOldModel = oldModel; prevNewModel = newModel; presentNode = presentNode->parentNode; } } HrcNodeFreeRecursively(oldNode); return TRUE; } /**Function******************************************************************** Synopsis [Checks whether node1 is part of the tree whose root is node2.] Description [The function returns TRUE if node1 is part of the sub-tree whose root is node2. Otherwise, it returns FALSE.] SideEffects [] SeeAlso [Hrc_TreeReplace()] ******************************************************************************/ boolean Hrc_NodeTestIsInTree( Hrc_Node_t *node1, Hrc_Node_t *node2) { /* node1 is the node whose membership is to be tested */ /* node2 is the root of the tree which is to be searched */ st_generator *gen; char *name; Hrc_Node_t *childNode; if(node1 == node2) { return TRUE; } else { Hrc_NodeForEachChild(node2, gen, name, childNode) { if(Hrc_NodeTestIsInTree(node1, childNode)) { return TRUE; } } return FALSE; } } /**Function******************************************************************** Synopsis [ Test whether a hnode is uninterpreted] Description [ An uninterpreted node does not have tables, latches or children. This type of node is defined in BLIF-MV as follows: syntax/example: .subckt f1 t1 a <= x c => z b <= y this represents an instance of the uninterpreted function z = f1( x, y ). a <= b denotes formal variable a and actual variable b. Where a is a subckt input. a => b denotes formal variable a and actual variable b. Where a is a subckt output. All subckts, with the same model name, should have identical formal parameters. Note: previous .subckt syntax is still be supported. There is no model definition for uninterpreted subckt. ] SideEffects [] SeeAlso [Hrc_ModelTestIsUninterpreted] ******************************************************************************/ boolean Hrc_NodeTestIsUninterpreted( Hrc_Node_t *node ) { if( st_count( Hrc_NodeReadLatchTable( node ) ) || array_n( Hrc_NodeReadNameTables( node ) ) || st_count( Hrc_NodeReadChildTable( node ) ) ) return FALSE; return TRUE; } /**Function******************************************************************** Synopsis [Checks if a model is uninterpreted.] Description [] SideEffects [] SeeAlso [Hrc_NodeTestIsUninterpreted] ******************************************************************************/ boolean Hrc_ModelTestIsUninterpreted( Hrc_Model_t* model ) { Hrc_Node_t* node; node = Hrc_ModelReadMasterNode( model ); if( st_count( Hrc_NodeReadLatchTable( node ) ) || array_n( Hrc_NodeReadNameTables( node ) ) || st_count( Hrc_ModelReadSubcktTable( model ) ) ) return FALSE; return TRUE; } /**Function******************************************************************** Synopsis [ Checks for the existence of an uninterpreted node in the hierarchy below the parent.] Description [ Determines if there is a child hnode below the parent is uninterpreted.] SideEffects [] SeeAlso [] ******************************************************************************/ boolean Hrc_NodeTestRecursivelyIsUninterpreted( Hrc_Node_t* parent ) { st_generator* gen; char* childName; Hrc_Node_t* child; if( Hrc_NodeTestIsUninterpreted( parent )) return TRUE; Hrc_NodeForEachChild( parent, gen, childName, child) { if( Hrc_NodeTestRecursivelyIsUninterpreted( child ) ) return TRUE; } return FALSE; } /**Function******************************************************************** Synopsis [ Checks for an uninterpreted node in hierarchy.] Description [ Determines if there is a node in the hierarchy that is uninterpreted.] SideEffects [] SeeAlso [] *****************************************************************************/ boolean Hrc_NodeTestIsUninterpretedNodeInHierarchy( Hrc_Manager_t* hmgr ) { return Hrc_NodeTestRecursivelyIsUninterpreted( Hrc_ManagerReadRootNode( hmgr ) ); } /**Function******************************************************************** Synopsis [Returns 1 if all the variables of a given node are consistent. Otherwise 0 is returned.] Description [Checks if all the variables in a given node are consistent in terms of labeling of six attributes (PI,PO,PS,NS,SI,SO) and the numFanoutTables field. Returns 1 if consistent. Otherwise 0 is returned. The function can be used for a sanity check after restructuring the hrc data structure.] SideEffects [None] SeeAlso [] ******************************************************************************/ boolean Hrc_NodeCheckVariableConsistency( Hrc_Node_t *node) { boolean success = TRUE; int i, j; st_generator *gen; Var_Variable_t *var; Hrc_Latch_t *latch; char *latchName, *varName; st_table *varToNumFanoutTables; Tbl_Table_t *table; long num; Hrc_NodeForEachFormalInput(node,i,var){ if (Var_VariableTestIsPI(var) == 0){ fprintf(vis_stderr, "Input variable %s is not labeled as PI.\n", Var_VariableReadName(var)); success = FALSE; } } Hrc_NodeForEachFormalOutput(node,i,var){ if (Var_VariableTestIsPO(var) == 0){ fprintf(vis_stderr, "Output variable %s is not labeled as PO.\n", Var_VariableReadName(var)); success = FALSE; } } /* if the node is not the root node, check consistency of actual variables */ if (Hrc_NodeReadParentNode(node) != NIL(Hrc_Node_t)){ Hrc_NodeForEachActualInput(node,i,var){ if (Var_VariableTestIsSI(var) == 0){ fprintf(vis_stderr, "Subcircuit input variable %s is not labeled as SI.\n", Var_VariableReadName(var)); success = FALSE; } } Hrc_NodeForEachActualOutput(node,i,var){ if (Var_VariableTestIsSO(var) == 0){ fprintf(vis_stderr, "Subcircuit output variable %s is not labeled as SO.\n", Var_VariableReadName(var)); success = FALSE; } } } Hrc_NodeForEachLatch(node,gen,latchName,latch){ var = Hrc_LatchReadOutput(latch); if (Var_VariableTestIsPS(var) == 0){ fprintf(vis_stderr, "Latch output variable %s is not labeled as PS.\n", Var_VariableReadName(var)); success = FALSE; } var = Hrc_LatchReadInput(latch); if (Var_VariableTestIsNS(var) == 0){ fprintf(vis_stderr, "Latch input variable %s is not labeled as NS.\n", Var_VariableReadName(var)); success = FALSE; } } varToNumFanoutTables = st_init_table(st_ptrcmp,st_ptrhash); Hrc_NodeForEachVariable(node,gen,varName,var){ if (Var_VariableTestTypeConsistency(var) == 0){ success = FALSE; } (void)st_insert(varToNumFanoutTables, (char *)var, (char *)((long)0)); } Hrc_NodeForEachNameTable(node,i,table){ Tbl_TableForEachInputVar(table,j,var){ (void)st_lookup(varToNumFanoutTables,var,&num); st_insert(varToNumFanoutTables,var,(char *) ++num); } } Hrc_NodeForEachVariable(node,gen,varName,var){ (void)st_lookup(varToNumFanoutTables,var,&num); if (num != (long)Var_VariableReadNumFanoutTables(var)){ fprintf(vis_stderr,"numFanoutTables field of variable %s is inconsistent. (True value = %d, Registered value = %d)\n", Var_VariableReadName(var), (int)num, Var_VariableReadNumFanoutTables(var)); success = FALSE; } } st_free_table(varToNumFanoutTables); return success; } /*---------------------------------------------------------------------------*/ /* Definition of internal functions */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Definition of static functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [A recursive function which inserts the names of all models used in the construction of a node into the hash table models.] SideEffects [] SeeAlso [Hrc_ManagerObtainComponentModels()] ******************************************************************************/ static void NodeObtainComponentModels( Hrc_Node_t *node, st_table *models) { char *name; Hrc_Node_t *child; st_generator *gen; st_insert(models, node->modelName, (char *) 0); Hrc_NodeForEachChild(node, gen, name, child){ NodeObtainComponentModels(child, models); } }