[14] | 1 | /**CFile*********************************************************************** |
---|
| 2 | |
---|
| 3 | FileName [resLayer.c] |
---|
| 4 | |
---|
| 5 | PackageName [res] |
---|
| 6 | |
---|
| 7 | Synopsis [This file is responsible for computing the "layers" in a circuit |
---|
| 8 | depending on the method] |
---|
| 9 | |
---|
| 10 | Author [Kavita Ravi <ravi@boulder.colorado.edu> and |
---|
| 11 | Abelardo Pardo <abel@boulder.colorado.edu>] |
---|
| 12 | |
---|
| 13 | Copyright [This file was created at the University of Colorado at Boulder. |
---|
| 14 | The University of Colorado at Boulder makes no warranty about the suitability |
---|
| 15 | of this software for any purpose. It is presented on an AS IS basis.] |
---|
| 16 | |
---|
| 17 | ******************************************************************************/ |
---|
| 18 | |
---|
| 19 | #include "resInt.h" |
---|
| 20 | |
---|
| 21 | static char rcsid[] UNUSED = "$Id: resLayer.c,v 1.36 2005/04/16 07:31:03 fabio Exp $"; |
---|
| 22 | |
---|
| 23 | /*---------------------------------------------------------------------------*/ |
---|
| 24 | /* Constant declarations */ |
---|
| 25 | /*---------------------------------------------------------------------------*/ |
---|
| 26 | |
---|
| 27 | /*---------------------------------------------------------------------------*/ |
---|
| 28 | /* Structure declarations */ |
---|
| 29 | /*---------------------------------------------------------------------------*/ |
---|
| 30 | |
---|
| 31 | /*---------------------------------------------------------------------------*/ |
---|
| 32 | /* Type declarations */ |
---|
| 33 | /*---------------------------------------------------------------------------*/ |
---|
| 34 | |
---|
| 35 | /*---------------------------------------------------------------------------*/ |
---|
| 36 | /* Variable declarations */ |
---|
| 37 | /*---------------------------------------------------------------------------*/ |
---|
| 38 | |
---|
| 39 | /*---------------------------------------------------------------------------*/ |
---|
| 40 | /* Macro declarations */ |
---|
| 41 | /*---------------------------------------------------------------------------*/ |
---|
| 42 | |
---|
| 43 | /**AutomaticStart*************************************************************/ |
---|
| 44 | |
---|
| 45 | /*---------------------------------------------------------------------------*/ |
---|
| 46 | /* Static function prototypes */ |
---|
| 47 | /*---------------------------------------------------------------------------*/ |
---|
| 48 | |
---|
| 49 | static array_t * ComputeCompositionLayersAsap(Ntk_Network_t *network, array_t *outputArray, array_t *ignoreArray); |
---|
| 50 | static array_t * ComputeCompositionLayersAlap(Ntk_Network_t *network, array_t *outputArray, array_t *ignoreArray); |
---|
| 51 | static int ComputeAlapLabelling(Ntk_Network_t *network, st_table *nodeLabelling); |
---|
| 52 | static void ComputeAlapLabellingRecur(Ntk_Node_t *node, st_table *nodeLabelling); |
---|
| 53 | static st_table * ComputeTransitiveFanin(array_t *outputArray); |
---|
| 54 | static void ComputeTransitiveFaninRecur(Ntk_Node_t *nodePtr, st_table *faninTable); |
---|
| 55 | static void RecursiveDecrementFanoutCount(Ntk_Node_t *nodePtr, st_table *fanoutCountTable, st_table *visitedTable); |
---|
| 56 | |
---|
| 57 | /**AutomaticEnd***************************************************************/ |
---|
| 58 | |
---|
| 59 | |
---|
| 60 | /*---------------------------------------------------------------------------*/ |
---|
| 61 | /* Definition of exported functions */ |
---|
| 62 | /*---------------------------------------------------------------------------*/ |
---|
| 63 | |
---|
| 64 | |
---|
| 65 | /*---------------------------------------------------------------------------*/ |
---|
| 66 | /* Definition of internal functions */ |
---|
| 67 | /*---------------------------------------------------------------------------*/ |
---|
| 68 | |
---|
| 69 | /**Function******************************************************************** |
---|
| 70 | |
---|
| 71 | Synopsis [Computes the layers of nodes of the network that represent the order |
---|
| 72 | for composition.] |
---|
| 73 | |
---|
| 74 | Description [ Computes the layers of nodes of the network that represent the |
---|
| 75 | order for composition. When composing an ADD with nodes in the circuit |
---|
| 76 | starting with the primary outputs, several nodes in the network can be |
---|
| 77 | composed at the same time producing "layers" in the network. When a node is |
---|
| 78 | in the layer and it is composed with its fanin nodes, the original node does |
---|
| 79 | not belong to the ADD any more, and its fanin nodes become now part of the |
---|
| 80 | ADD. There are several ways to produce this cut, we provide two such |
---|
| 81 | methods. This procedure reads the flag <tt>residue_layers<\tt> and calls the |
---|
| 82 | pertinent function. The procedure takes as arguments the network whose layers |
---|
| 83 | need to be formed, the set of outputs that need to be considered and the set |
---|
| 84 | of outputs that can be ignored. The procedure returns an array of layers] |
---|
| 85 | |
---|
| 86 | SideEffects [] |
---|
| 87 | |
---|
| 88 | SeeAlso [ComputeCompositionLayersAsap ComputeCompositionLayersAlap] |
---|
| 89 | |
---|
| 90 | ******************************************************************************/ |
---|
| 91 | array_t * |
---|
| 92 | ResComputeCompositionLayers(Ntk_Network_t *network, |
---|
| 93 | array_t *outputArray, |
---|
| 94 | array_t *ignoreArray) |
---|
| 95 | { |
---|
| 96 | ResLayerScheduleMethod layerMethod; /* read from the set value */ |
---|
| 97 | array_t *result; /* Result obtained from procedure */ |
---|
| 98 | char *flagValue; /* To store the value read from the flag */ |
---|
| 99 | |
---|
| 100 | /* Read the value from the flag */ |
---|
| 101 | flagValue = Cmd_FlagReadByName("residue_layer_schedule"); |
---|
| 102 | if (flagValue == NIL(char)) { |
---|
| 103 | layerMethod = ResDefaultScheduleLayerMethod_c; |
---|
| 104 | } |
---|
| 105 | else { |
---|
| 106 | if (strcmp(flagValue, "asap") == 0) { |
---|
| 107 | layerMethod = ResLayerAsap_c; |
---|
| 108 | } |
---|
| 109 | else if (strcmp(flagValue, "alap") == 0) { |
---|
| 110 | layerMethod = ResLayerAlap_c; |
---|
| 111 | } |
---|
| 112 | else { |
---|
| 113 | (void) fprintf(vis_stderr, "** res error: Unknown method to compute layers."); |
---|
| 114 | (void) fprintf(vis_stderr, "** res error: Assuming default method.\n"); |
---|
| 115 | layerMethod = ResDefaultScheduleLayerMethod_c; |
---|
| 116 | } |
---|
| 117 | } |
---|
| 118 | |
---|
| 119 | /* Call the pertinent procedure */ |
---|
| 120 | switch (layerMethod) { |
---|
| 121 | case ResLayerAlap_c: { |
---|
| 122 | result = ComputeCompositionLayersAlap(network, outputArray, ignoreArray); |
---|
| 123 | break; |
---|
| 124 | } |
---|
| 125 | case ResLayerAsap_c: { |
---|
| 126 | result = ComputeCompositionLayersAsap(network, outputArray, ignoreArray); |
---|
| 127 | break; |
---|
| 128 | } |
---|
| 129 | default: { |
---|
| 130 | (void) fprintf(vis_stdout, "** res warning: Layer computation method not implemented."); |
---|
| 131 | (void) fprintf(vis_stdout, "** res warning: Executing default method.\n"); |
---|
| 132 | result = ComputeCompositionLayersAlap(network, outputArray, ignoreArray); |
---|
| 133 | break; |
---|
| 134 | } |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | return result; |
---|
| 138 | } /* End of ResComputeCompositionLayers */ |
---|
| 139 | |
---|
| 140 | |
---|
| 141 | /**Function******************************************************************** |
---|
| 142 | |
---|
| 143 | Synopsis [Prints out the different layers in the circuit.] |
---|
| 144 | |
---|
| 145 | Description [Prints the nodes in various layers starting with the output |
---|
| 146 | along with their layer numbers. The procedure also counts the number of new |
---|
| 147 | variables that the current layer brings in. The procedure takes the network |
---|
| 148 | whose layers are to be printed and the layer array structure.] |
---|
| 149 | |
---|
| 150 | SideEffects [] |
---|
| 151 | |
---|
| 152 | SeeAlso [Res_NetworkResidueVerify] |
---|
| 153 | |
---|
| 154 | ******************************************************************************/ |
---|
| 155 | void |
---|
| 156 | ResLayerPrintInfo(Ntk_Network_t *network, |
---|
| 157 | array_t *layerArray) |
---|
| 158 | { |
---|
| 159 | |
---|
| 160 | Ntk_Node_t *nodePtr, *faninNodePtr; /* Node being processed */ |
---|
| 161 | st_table *faninTable; /* Current nodes */ |
---|
| 162 | int layerIndex, newVars; /* index of the layer being processed */ |
---|
| 163 | int i,j; /* For array traversal */ |
---|
| 164 | array_t *currentLayer; /* layer info */ |
---|
| 165 | |
---|
| 166 | /* keep track of all nodes that have appeared in the support */ |
---|
| 167 | faninTable = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 168 | /* Loop over the number of elements in layerArray */ |
---|
| 169 | for (layerIndex = 0; layerIndex < array_n(layerArray); layerIndex++) { |
---|
| 170 | /* reset new variables in the support of this array */ |
---|
| 171 | newVars = 0; |
---|
| 172 | |
---|
| 173 | (void) fprintf(vis_stdout, "Layer %d: ", layerIndex); |
---|
| 174 | |
---|
| 175 | /* Access the layer info */ |
---|
| 176 | currentLayer = ResLayerFetchIthLayer(layerArray, layerIndex); |
---|
| 177 | |
---|
| 178 | /* Print the nodes in a layer that are not PIs */ |
---|
| 179 | LayerForEachNode(currentLayer, i, nodePtr) { |
---|
| 180 | (void) fprintf(vis_stdout, "%s ", Ntk_NodeReadName(nodePtr)); |
---|
| 181 | |
---|
| 182 | /* store fanin nodes in the table, keep count */ |
---|
| 183 | Ntk_NodeForEachFanin(nodePtr, j, faninNodePtr) { |
---|
| 184 | if (!st_is_member(faninTable, (char *)faninNodePtr)) { |
---|
| 185 | if (!((Ntk_NodeTestIsLatch(nodePtr) && |
---|
| 186 | (Ntk_NodeTestIsLatchDataInput(faninNodePtr) || |
---|
| 187 | Ntk_NodeTestIsLatchInitialInput(faninNodePtr))) || |
---|
| 188 | Ntk_NodeTestIsConstant(faninNodePtr))) { |
---|
| 189 | |
---|
| 190 | st_insert(faninTable, (char *)faninNodePtr, NIL(char)); |
---|
| 191 | newVars++; |
---|
| 192 | } |
---|
| 193 | } |
---|
| 194 | } |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | (void) fprintf(vis_stdout,": SUPPORT = %d", newVars); |
---|
| 198 | (void) fprintf(vis_stdout, "\n"); |
---|
| 199 | |
---|
| 200 | |
---|
| 201 | } /* End of for every layer */ |
---|
| 202 | |
---|
| 203 | /* Clean up */ |
---|
| 204 | st_free_table(faninTable); |
---|
| 205 | return; |
---|
| 206 | } /* End of ResLayerPrintInfo */ |
---|
| 207 | |
---|
| 208 | |
---|
| 209 | /**Function******************************************************************** |
---|
| 210 | |
---|
| 211 | Synopsis [Free the layer information computed for each network.] |
---|
| 212 | |
---|
| 213 | Description [Free the layer information computed for each network. Takes the |
---|
| 214 | layer structure to be freed as the argument.] |
---|
| 215 | |
---|
| 216 | SideEffects [] |
---|
| 217 | |
---|
| 218 | SeeAlso [Res_NetworkResidueVerify] |
---|
| 219 | |
---|
| 220 | ******************************************************************************/ |
---|
| 221 | void |
---|
| 222 | ResLayerArrayFree(array_t *layerArray) |
---|
| 223 | { |
---|
| 224 | int i, end; |
---|
| 225 | array_t *currentLayer; |
---|
| 226 | |
---|
| 227 | i = 0; |
---|
| 228 | end = array_n(layerArray); |
---|
| 229 | for (i =0; i < end ; i++) { |
---|
| 230 | currentLayer = ResLayerFetchIthLayer(layerArray, i); |
---|
| 231 | LayerFree(currentLayer); |
---|
| 232 | } |
---|
| 233 | array_free(layerArray); |
---|
| 234 | } /* End of ResLayerArrayFree */ |
---|
| 235 | |
---|
| 236 | /*---------------------------------------------------------------------------*/ |
---|
| 237 | /* Definition of static functions */ |
---|
| 238 | /*---------------------------------------------------------------------------*/ |
---|
| 239 | |
---|
| 240 | /**Function******************************************************************** |
---|
| 241 | |
---|
| 242 | Synopsis [Computes the layers of nodes of the network based on the "as soon |
---|
| 243 | as possible" heuristic.] |
---|
| 244 | |
---|
| 245 | Description [Computes the layers of nodes of the network based on the "as |
---|
| 246 | soon as possible" heuristic. When composing an Add with nodes starting from |
---|
| 247 | the primary outputs, to the primary inputs, several nodes in the network are |
---|
| 248 | candidates for composition simultaneously producing what we decided to call |
---|
| 249 | "layers". This procedure schedules the composition of the nodes as soon as |
---|
| 250 | possible under the "One-Time Rule" restriction. The One-Time Rule states that |
---|
| 251 | a node may be composed into the ADD only when all its fanouts have been |
---|
| 252 | composed in. The "as soon as possible" schedule is such that a node n is |
---|
| 253 | composed with its fanin nodes f1,...,fn AS SOON AS all its fanouts have been |
---|
| 254 | composed. The procedure returns an array of layers. Each node appears in only |
---|
| 255 | one layer. The procedure takes as arguments the network whose layers are |
---|
| 256 | required, the outputs to be considered and the outputs to be ignored.] |
---|
| 257 | |
---|
| 258 | SideEffects [] |
---|
| 259 | |
---|
| 260 | SeeAlso [Res_NetworkResidueVerify ComputeCompositionLayersAlap] |
---|
| 261 | |
---|
| 262 | ******************************************************************************/ |
---|
| 263 | static array_t * |
---|
| 264 | ComputeCompositionLayersAsap(Ntk_Network_t *network, |
---|
| 265 | array_t *outputArray, |
---|
| 266 | array_t *ignoreArray) |
---|
| 267 | { |
---|
| 268 | Ntk_Node_t *nodePtr, *faninNodePtr; /* variables to store node pointers */ |
---|
| 269 | int i, j, k; /* iterators */ |
---|
| 270 | st_generator *stGen; /* generator to step through st_table */ |
---|
| 271 | char *key; /* values to read from st_table */ |
---|
| 272 | lsGen listGen; /* list generator to step through nodes */ |
---|
| 273 | array_t *currentLayer, *nextLayer; /* array of nodes belonging to a layer */ |
---|
| 274 | array_t *layerArray; /* array of layers */ |
---|
| 275 | st_table *fanoutCountTable; /* table to store fanout counts of each |
---|
| 276 | * node |
---|
| 277 | */ |
---|
| 278 | int fanoutCount; /* variable to store fanout count of a |
---|
| 279 | * node |
---|
| 280 | */ |
---|
| 281 | int value; /* to read value off the st_table */ |
---|
| 282 | st_table *visitedTable; /* table to store visited nodes */ |
---|
| 283 | |
---|
| 284 | /* create a fanout count table starting with all nodes except PIs, |
---|
| 285 | * constant node or a shadow node for any node but a latch(counts as |
---|
| 286 | * comb output). |
---|
| 287 | */ |
---|
| 288 | fanoutCountTable = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 289 | Ntk_NetworkForEachNode(network, listGen, nodePtr) { |
---|
| 290 | /* does not nodes like PIs, shadow nodes, constants, undefined |
---|
| 291 | * nodes to compute the fanouts, since they do not have to be |
---|
| 292 | * composed into the circuit. |
---|
| 293 | */ |
---|
| 294 | if ((Ntk_NodeTestIsCombOutput(nodePtr)) || |
---|
| 295 | (!(Ntk_NodeTestIsCombInput(nodePtr) || |
---|
| 296 | Ntk_NodeTestIsConstant(nodePtr) || |
---|
| 297 | Ntk_NodeTestIsUndefined(nodePtr) || |
---|
| 298 | Ntk_NodeTestIsShadow(nodePtr)))) { |
---|
| 299 | st_insert(fanoutCountTable, (char *)nodePtr, |
---|
| 300 | (char *)(long)Ntk_NodeReadNumFanouts(nodePtr)); |
---|
| 301 | } |
---|
| 302 | } |
---|
| 303 | |
---|
| 304 | /* take out outputs in directly verified table, if so desired */ |
---|
| 305 | /* Assume ignore table has node pointers , reduce fanout count of |
---|
| 306 | * transitive fanin of these nodes |
---|
| 307 | */ |
---|
| 308 | if (ignoreArray != NULL) { |
---|
| 309 | visitedTable = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 310 | arrayForEachItem(Ntk_Node_t *, ignoreArray, i, nodePtr) { |
---|
| 311 | /* each key is an output node */ |
---|
| 312 | RecursiveDecrementFanoutCount(nodePtr, fanoutCountTable, visitedTable); |
---|
| 313 | } |
---|
| 314 | st_free_table(visitedTable); |
---|
| 315 | |
---|
| 316 | /* remove all nodes that are primary inputs and those with fanout |
---|
| 317 | * count 0 providing they are not primary outputs/ or latch inputs |
---|
| 318 | * or latch initial values. |
---|
| 319 | */ |
---|
| 320 | st_foreach_item_int(fanoutCountTable, stGen, &key, &value) { |
---|
| 321 | fanoutCount = value; |
---|
| 322 | nodePtr = (Ntk_Node_t *)key; |
---|
| 323 | assert(fanoutCount >= -1); |
---|
| 324 | if ((!Ntk_NodeTestIsCombOutput(nodePtr)) |
---|
| 325 | && (fanoutCount <= 0)) { |
---|
| 326 | /* delete the item corresponding to fanoutCount i.e. value */ |
---|
| 327 | st_delete_int(fanoutCountTable, (char **)&key, &value); |
---|
| 328 | } |
---|
| 329 | } |
---|
| 330 | /* remove all outputs that belong to ignore outputs */ |
---|
| 331 | arrayForEachItem(Ntk_Node_t *, ignoreArray, i, nodePtr) { |
---|
| 332 | st_delete_int(fanoutCountTable, &nodePtr, &value); |
---|
| 333 | } |
---|
| 334 | } |
---|
| 335 | |
---|
| 336 | /* start preparing the layer array */ |
---|
| 337 | layerArray = array_alloc(array_t *, 0); |
---|
| 338 | currentLayer = LayerCreateEmptyLayer(); |
---|
| 339 | |
---|
| 340 | /* outputs form the first layer */ |
---|
| 341 | Ntk_NetworkForEachCombOutput(network, listGen, nodePtr) { |
---|
| 342 | if (st_lookup_int(fanoutCountTable, (char *)nodePtr, &fanoutCount)) { |
---|
| 343 | /* insert all outputs that aren't to be ignored in the first layer of the |
---|
| 344 | * layer array |
---|
| 345 | */ |
---|
| 346 | LayerAddNodeAtEnd(currentLayer, nodePtr); |
---|
| 347 | } |
---|
| 348 | } |
---|
| 349 | |
---|
| 350 | /* if current layer is not empty */ |
---|
| 351 | while (ResLayerNumNodes(currentLayer) ) { |
---|
| 352 | /* insert current layer into layer array */ |
---|
| 353 | array_insert_last(array_t *, layerArray, currentLayer); |
---|
| 354 | nextLayer = LayerCreateEmptyLayer(); |
---|
| 355 | LayerForEachNode(currentLayer, i, nodePtr) { |
---|
| 356 | Ntk_NodeForEachFanin(nodePtr, j, faninNodePtr) { |
---|
| 357 | /* do not want to get the fanin for latch outputs */ |
---|
| 358 | if(!(Ntk_NodeTestIsConstant(nodePtr) || |
---|
| 359 | (Ntk_NodeTestIsLatch(nodePtr) && |
---|
| 360 | (Ntk_NodeTestIsLatchDataInput(faninNodePtr) || |
---|
| 361 | Ntk_NodeTestIsLatchInitialInput(faninNodePtr))))) { |
---|
| 362 | if (!st_lookup_int(fanoutCountTable, (char *)faninNodePtr, |
---|
| 363 | &fanoutCount)) { |
---|
| 364 | /* maybe it is a PI or constant node */ |
---|
| 365 | if (!(Ntk_NodeTestIsCombInput(faninNodePtr) || |
---|
| 366 | Ntk_NodeTestIsConstant(faninNodePtr) || |
---|
| 367 | Ntk_NodeTestIsUndefined(faninNodePtr) || |
---|
| 368 | Ntk_NodeTestIsShadow(faninNodePtr))) { |
---|
| 369 | error_append("Fanin node %s should have been in table"); |
---|
| 370 | error_append(Ntk_NodeReadName(faninNodePtr)); |
---|
| 371 | /* Cleanup */ |
---|
| 372 | arrayForEachItem(array_t *, layerArray, k, currentLayer) { |
---|
| 373 | LayerFree(currentLayer); |
---|
| 374 | } |
---|
| 375 | array_free(layerArray); |
---|
| 376 | return NIL(array_t); |
---|
| 377 | } /* node is neither PI nor constant */ |
---|
| 378 | } else { /* node is found in table */ |
---|
| 379 | fanoutCount--; |
---|
| 380 | /* decrement fanout count, will go into a later layer */ |
---|
| 381 | if (fanoutCount == 0) { |
---|
| 382 | /* |
---|
| 383 | * it is ready to be put in the array, |
---|
| 384 | * since its fanout count is 1 |
---|
| 385 | */ |
---|
| 386 | LayerAddNodeAtEnd(nextLayer, faninNodePtr); |
---|
| 387 | } else if (fanoutCount > 0) { |
---|
| 388 | /* insert new decremented value in table */ |
---|
| 389 | st_insert(fanoutCountTable, (char *)faninNodePtr, |
---|
| 390 | (char *)(long)fanoutCount); |
---|
| 391 | |
---|
| 392 | } /* end of nodes fanout count larger than 1 */ |
---|
| 393 | } /* end of fanin node found in fanout count table */ |
---|
| 394 | } /* do not want to get the fanin for latch outputs */ |
---|
| 395 | } /* end of iteration through all the fanin nodes of current node */ |
---|
| 396 | } /* end of iteration through all the nodes of current layer */ |
---|
| 397 | /* the fanout count ensures unique entry of elements ????*/ |
---|
| 398 | currentLayer = nextLayer; |
---|
| 399 | } /* end of while some nodes in current layer */ |
---|
| 400 | |
---|
| 401 | /* the loop always exits with an empty array */ |
---|
| 402 | LayerFree(currentLayer); |
---|
| 403 | st_free_table(fanoutCountTable); |
---|
| 404 | if (array_n(layerArray) == 0) { |
---|
| 405 | array_free(layerArray); |
---|
| 406 | layerArray = NIL(array_t); |
---|
| 407 | } |
---|
| 408 | |
---|
| 409 | return (layerArray); |
---|
| 410 | |
---|
| 411 | } /* End of ComputeCompositionLayersAsap */ |
---|
| 412 | |
---|
| 413 | /**Function********************************************************************** |
---|
| 414 | |
---|
| 415 | Synopsis [ Computes the layers of nodes of the network based on the "as late |
---|
| 416 | as possible" heuristic.] |
---|
| 417 | |
---|
| 418 | Description [ Computes the layers of nodes of the network based on the "as |
---|
| 419 | late as possible" heuristic. When composing an Add with nodes starting from |
---|
| 420 | the primary outputs, to the primary inputs, several nodes in the network are |
---|
| 421 | candidates for composition simultaneously producing what we decided to call |
---|
| 422 | "layers". This procedure schedules the composition of the nodes as late as |
---|
| 423 | possible under the "One-Time Rule" restriction. The One-Time Rule states that |
---|
| 424 | a node may be composed into the ADD only when all its fanouts have been |
---|
| 425 | composed in. This procedure schedules the composition of the nodes as "late" |
---|
| 426 | as possible i.e. only when no further composition can be done without |
---|
| 427 | composing the node in question. The order of composition is computed by |
---|
| 428 | labeling every node with its maximum distance from the primary inputs. The |
---|
| 429 | nodes are then scheduled starting with those with the larger depth and |
---|
| 430 | descending until reaching the inputs. Note that with this heuristic we still |
---|
| 431 | guarantee that every node appears in one single layer, therefore, it is only |
---|
| 432 | composed once. This is not "strictly as late as possible" as the symmetric |
---|
| 433 | opposite of the as soon as possible technique. But this scheduling has the |
---|
| 434 | additional win of taking advantage of the varying depths of the different |
---|
| 435 | paths in the circuit and scheduling the nodes evenly. The procedure takes as |
---|
| 436 | arguments the network whose layers are required, the outputs to be considered |
---|
| 437 | and the outputs to be ignored.] |
---|
| 438 | |
---|
| 439 | SideEffects [] |
---|
| 440 | |
---|
| 441 | SeeAlso [ResComputeCompositionLayers ComputeCompositionLayersAsap] |
---|
| 442 | |
---|
| 443 | ******************************************************************************/ |
---|
| 444 | static array_t * |
---|
| 445 | ComputeCompositionLayersAlap(Ntk_Network_t *network, |
---|
| 446 | array_t *outputArray, |
---|
| 447 | array_t *ignoreArray) |
---|
| 448 | { |
---|
| 449 | Ntk_Node_t *nodePtr; /* node being processed */ |
---|
| 450 | array_t *layerArray; /* array of layers */ |
---|
| 451 | array_t *currentLayer; /* layer of nodes */ |
---|
| 452 | st_table *nodeLabelling; /* labeling of a node, its farthest distance |
---|
| 453 | * from the primary input |
---|
| 454 | */ |
---|
| 455 | int numLayers; /* Number of Layers */ |
---|
| 456 | int layerIndex; /* index of a layer (from the primary output */ |
---|
| 457 | int arrayIndex; /* iterator */ |
---|
| 458 | st_generator *stGen; /* generator to step through table */ |
---|
| 459 | char *key; /* values to read from table */ |
---|
| 460 | int value; /* integer value to read from the table */ |
---|
| 461 | |
---|
| 462 | /* Initialize the labeling table */ |
---|
| 463 | nodeLabelling = ComputeTransitiveFanin(outputArray); |
---|
| 464 | |
---|
| 465 | /* Compute the labeling of the nodes */ |
---|
| 466 | numLayers = ComputeAlapLabelling(network, nodeLabelling); |
---|
| 467 | |
---|
| 468 | /* Create the layerArray structure */ |
---|
| 469 | layerArray = array_alloc(array_t *, numLayers); |
---|
| 470 | /* initialize layers */ |
---|
| 471 | for (layerIndex = 0; layerIndex < numLayers; layerIndex++) { |
---|
| 472 | currentLayer = LayerCreateEmptyLayer(); |
---|
| 473 | array_insert(array_t *, layerArray, layerIndex, currentLayer); |
---|
| 474 | } /* end of for */ |
---|
| 475 | |
---|
| 476 | /* insert elements of the st_table in the layers */ |
---|
| 477 | st_foreach_item_int(nodeLabelling, stGen, &key, &value) { |
---|
| 478 | layerIndex = value; |
---|
| 479 | nodePtr = (Ntk_Node_t *)key; |
---|
| 480 | /* don't put PIs or comb inputs or constants or undefined |
---|
| 481 | * nodes in layer array |
---|
| 482 | */ |
---|
| 483 | if ((Ntk_NodeTestIsCombOutput(nodePtr)) || |
---|
| 484 | ((layerIndex > 0) && |
---|
| 485 | !(Ntk_NodeTestIsCombInput(nodePtr) || |
---|
| 486 | Ntk_NodeTestIsConstant(nodePtr) || |
---|
| 487 | Ntk_NodeTestIsUndefined(nodePtr) || |
---|
| 488 | Ntk_NodeTestIsShadow(nodePtr)))) { |
---|
| 489 | /* the layers are arranged in reverse order of their farthest |
---|
| 490 | * distance from the node. Hence each node is inserted into |
---|
| 491 | * the numLayers-1-layerIndex. Nodes with layerIndex should be |
---|
| 492 | * put in the last array since they are probably constants |
---|
| 493 | * at the primary outputs or latch initial value. LayerIndex |
---|
| 494 | * could be 0 for primary outputs if it does not appear in the |
---|
| 495 | * transitive fanin of the comb inputs. |
---|
| 496 | */ |
---|
| 497 | if (layerIndex == 0) { |
---|
| 498 | arrayIndex = 0; |
---|
| 499 | assert(Ntk_NodeTestIsCombOutput(nodePtr) == 1); |
---|
| 500 | } else { |
---|
| 501 | arrayIndex = numLayers - layerIndex; |
---|
| 502 | } |
---|
| 503 | currentLayer = array_fetch(array_t *, layerArray, arrayIndex); |
---|
| 504 | LayerAddNodeAtEnd(currentLayer, nodePtr); |
---|
| 505 | } |
---|
| 506 | } |
---|
| 507 | /* Clean up */ |
---|
| 508 | st_free_table(nodeLabelling); |
---|
| 509 | |
---|
| 510 | |
---|
| 511 | return layerArray; |
---|
| 512 | } /* End of ComputeCompositionLayersAlap */ |
---|
| 513 | |
---|
| 514 | |
---|
| 515 | /**Function********************************************************************* |
---|
| 516 | |
---|
| 517 | Synopsis [ Procedure to label each node with its maximum distance from the |
---|
| 518 | primary inputs.] |
---|
| 519 | |
---|
| 520 | Description [The procedure processes iteratively every input. For each of |
---|
| 521 | them, it labels recursively its transitive output keeping always the larger |
---|
| 522 | depth value. The procedure accepts as arguments the network that need to be |
---|
| 523 | labeled and a table with the labeling of nodes to be filled) and returns the |
---|
| 524 | maximum layer size.] |
---|
| 525 | |
---|
| 526 | SideEffects [It modifies the st_table passed as parameter.] |
---|
| 527 | |
---|
| 528 | SeeAlso [ComputeCompositionLayersAlap ComputeAlapLabellingRecur] |
---|
| 529 | |
---|
| 530 | ******************************************************************************/ |
---|
| 531 | static int |
---|
| 532 | ComputeAlapLabelling(Ntk_Network_t *network, |
---|
| 533 | st_table *nodeLabelling) |
---|
| 534 | { |
---|
| 535 | Ntk_Node_t *nodePtr; /* Node being processed */ |
---|
| 536 | lsGen gen; /* For list traversal */ |
---|
| 537 | int numLayers; /* To return as result */ |
---|
| 538 | int outputDepth; /* Depth of the output being processed */ |
---|
| 539 | |
---|
| 540 | assert(nodeLabelling != NIL(st_table)); |
---|
| 541 | |
---|
| 542 | /* For primary inputs in the table (those not in the table |
---|
| 543 | * are in the transitive fanin of the ignored outputs only |
---|
| 544 | */ |
---|
| 545 | Ntk_NetworkForEachCombInput(network, gen, nodePtr) { |
---|
| 546 | /* do it for fanouts that are in table only */ |
---|
| 547 | if (st_is_member(nodeLabelling, (char *)nodePtr)) { |
---|
| 548 | ComputeAlapLabellingRecur(nodePtr, nodeLabelling); |
---|
| 549 | } |
---|
| 550 | } |
---|
| 551 | |
---|
| 552 | /* Compute the number of layers */ |
---|
| 553 | numLayers = 0; |
---|
| 554 | Ntk_NetworkForEachCombOutput(network, gen, nodePtr) { |
---|
| 555 | /* only those outputs not be to be ignored */ |
---|
| 556 | if (st_lookup_int(nodeLabelling, (char *)nodePtr, &outputDepth)) { |
---|
| 557 | if (outputDepth > numLayers ) { |
---|
| 558 | numLayers = outputDepth; |
---|
| 559 | } /* End of if */ |
---|
| 560 | } |
---|
| 561 | } |
---|
| 562 | |
---|
| 563 | return numLayers; |
---|
| 564 | } /* End of ComputeAlapLabelling */ |
---|
| 565 | |
---|
| 566 | /**Function********************************************************************* |
---|
| 567 | |
---|
| 568 | Synopsis [Recursive procedure to label every node with its maximum depth |
---|
| 569 | from the primary inputs.] |
---|
| 570 | |
---|
| 571 | Description [It labels every node with the current depth and |
---|
| 572 | proceeds recursively through the fanouts. The procedure accepts as |
---|
| 573 | its arguments the node it is currently recurring on and the table |
---|
| 574 | with labeling of the nodes(max distance from the PIs) which gets |
---|
| 575 | updated.] |
---|
| 576 | |
---|
| 577 | SideEffects [It modifies the st_table passed as parameter] |
---|
| 578 | |
---|
| 579 | SeeAlso [ComputeAlapLabelling] |
---|
| 580 | |
---|
| 581 | ******************************************************************************/ |
---|
| 582 | static void |
---|
| 583 | ComputeAlapLabellingRecur(Ntk_Node_t *node, |
---|
| 584 | st_table *nodeLabelling) |
---|
| 585 | { |
---|
| 586 | Ntk_Node_t *fanoutPtr; |
---|
| 587 | int nodeDepth; |
---|
| 588 | int fanoutDepth; |
---|
| 589 | int i; |
---|
| 590 | |
---|
| 591 | /* Trivial case */ |
---|
| 592 | if (Ntk_NodeReadNumFanouts(node) == 0) { |
---|
| 593 | return; |
---|
| 594 | } /* End of if */ |
---|
| 595 | |
---|
| 596 | /* Look up information for the current node */ |
---|
| 597 | st_lookup_int(nodeLabelling, (char *)node, &nodeDepth); |
---|
| 598 | |
---|
| 599 | /* Iterate over its fanouts */ |
---|
| 600 | Ntk_NodeForEachFanout(node, i, fanoutPtr) { |
---|
| 601 | /* Do not process as soon as an input is found beyond an output */ |
---|
| 602 | if (!((Ntk_NodeTestIsLatchDataInput(node) || |
---|
| 603 | Ntk_NodeTestIsLatchInitialInput(node)) && |
---|
| 604 | Ntk_NodeTestIsLatch(fanoutPtr))) { |
---|
| 605 | if (st_is_member(nodeLabelling, (char *)fanoutPtr)) { |
---|
| 606 | /* Look up information for the fanout */ |
---|
| 607 | st_lookup_int(nodeLabelling, (char *)fanoutPtr, &fanoutDepth); |
---|
| 608 | /* If the fanout depth needs to be modified, do so, and recur */ |
---|
| 609 | if (nodeDepth >= fanoutDepth) { |
---|
| 610 | st_insert(nodeLabelling, (char *)fanoutPtr, |
---|
| 611 | (char *)(long)(nodeDepth + 1)); |
---|
| 612 | ComputeAlapLabellingRecur(fanoutPtr, nodeLabelling); |
---|
| 613 | } /* End of if */ |
---|
| 614 | } /* End of if */ |
---|
| 615 | } /* End of if */ |
---|
| 616 | } /* End of for each fanout */ |
---|
| 617 | |
---|
| 618 | return; |
---|
| 619 | } /* End of ComputeAlapLabellingRecur */ |
---|
| 620 | |
---|
| 621 | |
---|
| 622 | /**Function********************************************************************* |
---|
| 623 | |
---|
| 624 | Synopsis [Procedure that computes the transitive fanin of a set |
---|
| 625 | of nodes in an array.] |
---|
| 626 | |
---|
| 627 | Description [[Procedure that computes the transitive fanin of a set |
---|
| 628 | of nodes in an array. The procedure puts the nodes themselves into the |
---|
| 629 | array too.The procedure takes as arguments the array whose transitive |
---|
| 630 | fanin need to be computed and returns an st_table with the fanin.] |
---|
| 631 | |
---|
| 632 | SideEffects [] |
---|
| 633 | |
---|
| 634 | SeeAlso [ComputeCompositionLayersAlap ComputeTransitiveFaninRecur] |
---|
| 635 | |
---|
| 636 | *****************************************************************************/ |
---|
| 637 | static st_table * |
---|
| 638 | ComputeTransitiveFanin(array_t *outputArray) |
---|
| 639 | { |
---|
| 640 | Ntk_Node_t *nodePtr; |
---|
| 641 | st_table * faninTable; |
---|
| 642 | int i; |
---|
| 643 | |
---|
| 644 | faninTable = st_init_table(st_ptrcmp, st_ptrhash); |
---|
| 645 | arrayForEachItem(Ntk_Node_t *, outputArray, i, nodePtr) { |
---|
| 646 | ComputeTransitiveFaninRecur(nodePtr, faninTable); |
---|
| 647 | } |
---|
| 648 | return faninTable; |
---|
| 649 | } /* End of ComputeTransitiveFanin */ |
---|
| 650 | |
---|
| 651 | /**Function********************************************************************* |
---|
| 652 | |
---|
| 653 | Synopsis [Recursive procedure to compute the transitive fanin of |
---|
| 654 | a node.] |
---|
| 655 | |
---|
| 656 | Description [ Recursive procedure to compute the transitive fanin of a |
---|
| 657 | node. After computing the transitive fanin, the node itself goes into the |
---|
| 658 | table. The procedure takes in as arguments the node it is recurring on and |
---|
| 659 | the table of fanin encountered.] |
---|
| 660 | |
---|
| 661 | SideEffects [] |
---|
| 662 | |
---|
| 663 | SeeAlso [ComputeTransitiveFanin] |
---|
| 664 | |
---|
| 665 | *****************************************************************************/ |
---|
| 666 | static void |
---|
| 667 | ComputeTransitiveFaninRecur(Ntk_Node_t *nodePtr, |
---|
| 668 | st_table *faninTable) |
---|
| 669 | { |
---|
| 670 | Ntk_Node_t *faninNodePtr; |
---|
| 671 | int i; |
---|
| 672 | |
---|
| 673 | if (st_lookup(faninTable, (char *)nodePtr, NIL(char *))) { |
---|
| 674 | return; |
---|
| 675 | } |
---|
| 676 | |
---|
| 677 | |
---|
| 678 | /* recur on fanin nodes */ |
---|
| 679 | Ntk_NodeForEachFanin(nodePtr, i, faninNodePtr) { |
---|
| 680 | /* Test this case cos other comb inputs have no fanins */ |
---|
| 681 | if (!((Ntk_NodeTestIsLatchDataInput(faninNodePtr) || |
---|
| 682 | Ntk_NodeTestIsLatchInitialInput(faninNodePtr)) && |
---|
| 683 | Ntk_NodeTestIsLatch(nodePtr))) { |
---|
| 684 | ComputeTransitiveFaninRecur(faninNodePtr, faninTable); |
---|
| 685 | } /* end of if */ |
---|
| 686 | } /* iterate over all fanins */ |
---|
| 687 | |
---|
| 688 | st_insert(faninTable, (char *)nodePtr, NIL(char)); |
---|
| 689 | return; |
---|
| 690 | |
---|
| 691 | } /* End of ComputeTransitiveFaninRecur */ |
---|
| 692 | |
---|
| 693 | /**Function********************************************************************* |
---|
| 694 | |
---|
| 695 | Synopsis [Function to decrement fanout count] |
---|
| 696 | |
---|
| 697 | Description [Recursive procedure that reduces the fanout count of the |
---|
| 698 | current node and recurs on its fanin. Stops when Pis or constant nodes are |
---|
| 699 | hit which have no fanins. The procedure takes in as arguments the current it |
---|
| 700 | is recurring on and the table with nodes and their fanout counts.] |
---|
| 701 | |
---|
| 702 | SideEffects [] |
---|
| 703 | |
---|
| 704 | SeeAlso [ComputeCompositionLayersAsap] |
---|
| 705 | |
---|
| 706 | *****************************************************************************/ |
---|
| 707 | static void |
---|
| 708 | RecursiveDecrementFanoutCount(Ntk_Node_t *nodePtr, |
---|
| 709 | st_table *fanoutCountTable, |
---|
| 710 | st_table *visitedTable) |
---|
| 711 | { |
---|
| 712 | Ntk_Node_t *faninNodePtr; |
---|
| 713 | int i, fanoutCount; |
---|
| 714 | |
---|
| 715 | /* the following kinds of nodes will not be in the table. */ |
---|
| 716 | if ((!Ntk_NodeTestIsCombOutput(nodePtr)) && |
---|
| 717 | (Ntk_NodeTestIsCombInput(nodePtr) || |
---|
| 718 | Ntk_NodeTestIsUndefined(nodePtr)|| |
---|
| 719 | Ntk_NodeTestIsConstant(nodePtr) || |
---|
| 720 | Ntk_NodeTestIsShadow(nodePtr))) { |
---|
| 721 | return; |
---|
| 722 | } |
---|
| 723 | /* all nodes called here should exist in table */ |
---|
| 724 | if (!st_lookup_int(fanoutCountTable, (char *)nodePtr, &fanoutCount)){ |
---|
| 725 | error_append("Node "); |
---|
| 726 | error_append(Ntk_NodeReadName(nodePtr)); |
---|
| 727 | error_append(" should have been in table\n"); |
---|
| 728 | return; |
---|
| 729 | } |
---|
| 730 | |
---|
| 731 | fanoutCount--; |
---|
| 732 | /* reduce fanout count of node */ |
---|
| 733 | st_insert(fanoutCountTable, (char *)nodePtr, (char *)(long)fanoutCount); |
---|
| 734 | /* if this node is visited, decrement its fanout but do not proceed |
---|
| 735 | * any further (i.e. do not proceed with its fanins |
---|
| 736 | */ |
---|
| 737 | if (st_is_member(visitedTable, (char *)nodePtr)) { |
---|
| 738 | return; |
---|
| 739 | } else { |
---|
| 740 | st_insert(visitedTable, (char *)nodePtr, NIL(char)); |
---|
| 741 | |
---|
| 742 | /* |
---|
| 743 | * recur with fanin nodes except nodes with no fanins (that arent in table) |
---|
| 744 | * and latch outputs |
---|
| 745 | */ |
---|
| 746 | Ntk_NodeForEachFanin(nodePtr, i, faninNodePtr) { |
---|
| 747 | /* may be a redundant test, since it will pop out in the first line of |
---|
| 748 | * the procedure anyways. |
---|
| 749 | */ |
---|
| 750 | if (!(Ntk_NodeTestIsConstant(faninNodePtr) || |
---|
| 751 | ((Ntk_NodeTestIsLatchDataInput(faninNodePtr) || |
---|
| 752 | Ntk_NodeTestIsLatchInitialInput(faninNodePtr)) && |
---|
| 753 | Ntk_NodeTestIsLatch(nodePtr)))) { |
---|
| 754 | RecursiveDecrementFanoutCount(faninNodePtr, fanoutCountTable, visitedTable); |
---|
| 755 | } |
---|
| 756 | } /* end of iterating over fanins */ |
---|
| 757 | } /* end of else if not visited */ |
---|
| 758 | return; |
---|
| 759 | } /* End of RecursiveDecrementFanoutCount */ |
---|