Removed VERSION from .gitignore and updated VERSION.
[xcircuit.git] / asg / place.c
blob3e8994c66772d7c89777e72b5dcc38bd2f4f2ddf
1 /************************************************************
2 **
3 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
4 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
5 ** ALL RIGHTS RESERVED
6 **
7 ** This software is distributed on an as-is basis
8 ** with no warranty implied or intended. No author
9 ** or distributor takes responsibility to anyone
10 ** regarding its use of or suitability.
12 ** The software may be distributed and modified
13 ** freely for academic and other non-commercial
14 ** use but may NOT be utilized or included in whole
15 ** or part within any commercial product.
17 ** This copyright notice must remain on all copies
18 ** and modified versions of this software.
20 ************************************************************/
22 /* file place.c */
23 /* ------------------------------------------------------------------------
24 * Placement routines spl 7/89
26 * "(Level #)" refers to calling depth from main()
27 * ------------------------------------------------------------------------
29 #include <stdio.h>
30 #include "externs.h"
31 #include "psfigs.h"
33 /*---------------------------------------------------------------
34 * Forward Declarations
35 *---------------------------------------------------------------
38 mlist *trace_path();
39 int init_string_arrays();
40 module *select_next_box();
41 int accept_node1(), accept_node2(), accept_node3(), accept_node4();
43 /*---------------------------------------------------------------
44 * Global (to this file) Declarations
45 *---------------------------------------------------------------
48 static float xgr = 0; /* center of "gravity" of current box */
49 static float ygr = 0;
50 static float xgbr = 0; /* center of "gravity" of currently placed boxes */
51 static float ygbr = 0;
53 static int xSideCount; /* number of conections for the dominant count in
54 "best_side..." */
55 static int ySideCount; /* number of conections for the next highest count in
56 "best_side..." */
58 static ctree *c_tree;
59 /* the stem upon which the cluster tree is built and maintained. */
61 static int clus1 = 0, clus2 = 0;
62 /* identifies the clusters that should be combined in the next clustering pass*/
64 static clist *c_list, *partition_tree;
65 /* lists of module numbers, and other stats needed for the clustering calculations */
67 static int d1 = 0, d2 = 0;
68 /* used to evaluate how cross-coupled modules/partitions are placed; <d1> rep-
69 * resents the depth from <m1> to <m2>, and <d2> the reverse. (see cross_coupled_p())
72 int rpl_merge_row[MAX_MOD]; /* Used to restore the connection matrix if a */
73 int rpl_scratch_row[MAX_MOD]; /* partition is clipped from the tree */
74 int rpl_merge_col[MAX_MOD];
75 int rpl_scratch_col[MAX_MOD];
77 /* ------------------------------------------------------------------------
78 * Clustering routines stf 8/89
79 * ------------------------------------------------------------------------
82 /*---------------------------------------------------------------
83 * Partition (Level 1)
84 * Cut up the set of modules into a set of sets.
85 * This is done by building the cluster tree until some limit is reached.
86 * Then the cluster tree is picked apart to assign the modules to their
87 * apropriate partitions. (These assignments are made to the .used
88 * portion of module_info[].)
89 *---------------------------------------------------------------
92 int partition()
93 { int p, done = 0;
95 int p_count = 0, cont = FALSE;
96 FILE *temp = (debug_level < -3)?fopen("tree_stats", "a"):NULL;
98 init_info();
100 build_clusters();
102 /* debugging - */
103 if (debug_level < -3)
105 fprintf(temp,"\nmax breadth = %d, height = %d\n",
106 print_ctree(temp,c_tree), tree_depth(c_tree,0));
107 fclose(temp);
110 partition_count = ilist_length(c_list);
112 init_string_arrays(partition_count);
114 if (debug_level < 0) /* debug */
115 fprintf(stderr,"tree broken into %d partitions.\n", partition_count);
117 for (p = partition_count; p > 0; p--)
119 assign_partitions(p);
122 build_connections(matrix_type); /* rebuild the connection table for modules */
124 return(partition_count);
127 /*---------------------------------------------------------------
128 * blockPartition() (Level 1)
129 * Cut up the set of modules into a set of sets.
130 * This is done by taking advantage of blockingclues in the namespace of the
131 * .ivf file. Modules are assigned to their apropriate partitions, and these
132 * assignments are made to the .used * portion of module_info[].
133 *---------------------------------------------------------------
136 int blockPartition()
138 int p, done = 0;
139 int p_count = 0, cont = FALSE;
141 init_info();
143 partition_count = interpret_block_assignments();
145 init_string_arrays(partition_count);
147 install_modules();
149 if (debug_level < 0) /* debug */
150 fprintf(stderr,"%d block partitions discovered.\n", partition_count);
152 build_connections(matrix_type); /* rebuild the connection table for modules */
154 return(partition_count);
158 /*----------------------------------------------------------------------------------*/
159 int nstrcomp(c1,c2)
160 /* Return TRUE if the two strings are equal, ignoring case */
161 char *c1,*c2;
163 if (strcasecmp(c1,c2) == 0) return(TRUE);
164 else return(FALSE);
166 /*---------------------------------------------------------------------------------*/
167 int interpret_block_assignments()
169 mlist *ml;
170 int i, p, partCount; /* <partCount> corresponds to the length of <table> */
171 list *l, *table = NULL;
172 char *blkName;
174 /* Loop through all of the names for the modules, and collect block names */
175 /* for each unique block name, create a separate partition */
176 partCount = 0;
178 for (ml = modules; ml != NULL; ml = ml->next)
180 i = strcspn(ml->this->name,"/");
181 blkName = strdup(ml->this->name);
182 blkName = strncpy(blkName, ml->this->name, i);
183 blkName[i] = '\0';
185 /* Handle the special case where no block name is given: */
186 if (nstrcomp(blkName,ml->this->name) == TRUE) blkName = "BLANK";
188 l = member((int *)blkName, table, nstrcomp);
189 if (l == NULL) /* New block name encountered */
191 /* Insert the new name into the table */
192 queue((int *)blkName, &table);
193 p = partCount += 1;
195 else /* Old block name encountered, calculate the corresponding partition */
197 p = partCount - list_length(l) + 1;
199 /* set the module information for use by the boxing and string routines */
200 module_info[ml->this->index].used = p;
203 for (l = table; l != NULL; l = l->next) /* Cleanup strings */
205 my_free(l->this);
207 free_list(table); /* Cleanup */
208 return(partCount);
212 /*---------------------------------------------------------------------------------*/
213 int install_modules()
215 mlist *ml;
216 int p;
218 for (ml = modules; ml != NULL; ml = ml->next)
220 /* Loop through all of the names for the modules, and collect block names */
222 p = module_info[ml->this->index].used; /* (Set previously) */
224 /* add the module to the appropriate partition: */
225 partitions[p] = (mlist *)concat_list(ml->this, partitions[p]);
228 /*---------------------------------------------------------------
229 * breadth_search (Level 2)
230 * This measures the maximum breadth of the given ctree, executing (*fn)()
231 * On each node element.
232 *--------------------------------------------------------------
234 int breadth_search(t, fn)
235 ctree *t;
236 int (*fn)(); /* the function to perform at every node */
239 clist *queue = NULL;
240 ctree *temp;
241 int this, next, breadth = 0;
243 if (t == NULL) return 0;
245 /* Load the queue and begin: */
246 indexed_list_insert(t,0,&queue);
247 this = 1; next = 0; breadth = 1;
249 /* Yank the first person off of the list, and add any children to the back */
252 temp = (ctree *)remove_indexed_element(0, &queue); /* dequeue the next item */
253 if (temp != NULL)
255 if (temp->left!=NULL) /* enque the left child */
257 indexed_list_insert(temp->left,ilist_length(queue),&queue);
258 next += 1;
261 if (temp->right!=NULL) /* enque the right child */
263 indexed_list_insert(temp->right,ilist_length(queue),&queue);
264 next += 1;
266 /* Now do something with the element: */
267 (*fn)(temp->this);
268 if (--this == 0) /* end of a layer */
270 breadth = MAX(breadth, next);
271 this = next; next = 0;
274 /* go on to the next thing in the queue */
275 } while (ilist_length(queue)!= 0);
276 return (breadth);
278 /*---------------------------------------------------------------
279 * tree_breadth (Level 2)
280 * This measures the maximum breadth of the given ctree
281 *--------------------------------------------------------------
283 int tree_breadth(t)
284 ctree *t;
286 clist *queue = NULL;
287 ctree *temp;
288 int this, next, breadth = 0;
290 if (t == NULL) return 0;
292 /* Load the queue and begin: */
293 indexed_list_insert(t,0,&queue);
294 this = 1; next = 0; breadth = 1;
296 /* Yank the first person off of the list, and add any children to the back */
299 temp = (ctree *)remove_indexed_element(0, &queue); /* dequeue the next item */
300 if (temp != NULL)
302 if (temp->left!=NULL) /* enque the left child */
304 indexed_list_insert(temp->left,ilist_length(queue),&queue);
305 next += 1;
308 if (temp->right!=NULL) /* enque the right child */
310 indexed_list_insert(temp->right,ilist_length(queue),&queue);
311 next += 1;
313 if (--this == 0) /* end of a layer */
315 breadth = MAX(breadth, next);
316 this = next; next = 0;
319 /* go on to the next thing in the queue */
320 } while (ilist_length(queue)!= 0);
321 return (breadth);
324 /*---------------------------------------------------------------
325 * tree_depth (Level 2)
326 * This measures the maximum depth of the given ctree
327 *--------------------------------------------------------------
329 int tree_depth(t, d)
330 ctree *t; int d;
332 int r=d, l=d;
334 if (t == NULL) return d;
335 else
337 if (t->right != NULL)
339 r = tree_depth(t->right, ++r);
341 if (t->left != NULL)
343 l = tree_depth(t->left, ++l);
345 return MAX(r, l);
349 /*---------------------------------------------------------------
350 * accept_node1 (Level 3)
351 * This examines the given tree node, and returns a binary acceptance
352 * as to whether or not it will be an acceptable partition.
353 * IT IS IMPORTANT TO NOTE how this function is used: As tree limbs are
354 * built, they are checked for acceptance. Limbs/leaves are added to the
355 * branch one at a time, and if the new addition makes a previously
356 * acceptable branch unacceptable, the old branch is saved as a partition,
357 * and the new addition takes it's place in the growing tree.
359 * VARIANT 1: A partition is acceptable if it has LE the preset number
360 * of connections (-c flag) AND it has LE the preset number of modules
361 * enclosed (-s flag).
362 *---------------------------------------------------------------
364 int accept_node1(limb)
365 ctree *limb;
366 { /* recall that this will be called on partial trees */
367 int l = (limb->left != NULL) ? limb->left->this->size : 0;
368 int r = (limb->right!= NULL) ? limb->right->this->size : 0;
369 int c;
371 int s = MIN(limb->this->size, l + r);
372 l = (limb->left != NULL) ? limb->left->this->connects : 0;
373 r = (limb->right != NULL) ? limb->right->this->connects : 0;
374 c = MIN(limb->this->connects, l + r);
376 if ((s <= max_partition_size) && (c <= max_partition_conn)) return(TRUE);
377 else if (s == 1) return(TRUE);
378 else return(FALSE);
381 /*---------------------------------------------------------------
382 * VARIANT 2: A partition is acceptable if the ratio of the number
383 * of connections to the number of modules is greater than some value
384 * partition_ratio (set by the -r flag).
385 *----------------------------------------------------------------
387 int accept_node2(limb)
388 ctree *limb;
389 { /* recall that this will be called on partial trees */
390 int c = limb->this->connects;
391 int s = limb->this->size;
392 float ratio;
394 ratio = (s > 0) ? (float)c/(float)s : 0.0;
396 if ((s == 1) || (ratio >= partition_ratio)) return(TRUE);
397 else return(FALSE);
399 /*---------------------------------------------------------------
400 * VARIANT 3: A partition is acceptable if the parent represents
401 * an increace in the total number of connections represented by the
402 * branch. (So a good partition will represent a local maxima)
403 *---------------------------------------------------------------
405 int accept_node3(limb)
406 ctree *limb;
407 { /* recall that this will be called on partial trees */
408 int s = limb->this->size;
409 int c = limb->this->connects;
410 int l = (limb->left != NULL) ? limb->left->this->connects : 0;
411 int r = (limb->right!= NULL) ? limb->right->this->connects : 0;
413 if ((s == 1) || ((c >= MAX(l,r)) && (c <= max_partition_conn)))
414 return(TRUE);
415 else return(FALSE);
417 /*---------------------------------------------------------------
418 * VARIANT 4: A partition is acceptable if the parent represents
419 * an increace in the ratio of the c/s among the branches...
420 * (So a good partition will represent a local c/s minima)
421 *---------------------------------------------------------------
423 int accept_node4(limb)
424 ctree *limb;
425 { /* recall that this will be called on partial trees */
426 int s = limb->this->size;
427 int c = limb->this->connects;
428 int cl = (limb->left != NULL) ? limb->left->this->connects : 0;
429 int cr = (limb->right!= NULL) ? limb->right->this->connects : 0;
430 int sl = (limb->left != NULL) ? limb->left->this->size : 0;
431 int sr = (limb->right!= NULL) ? limb->right->this->size : 0;
432 float OVratio, Lratio, Rratio, maxChildRatio;
434 OVratio = (s != 0) ? (float)c/(float)s : 0.0;
435 Lratio = (sl != 0) ? (float)cl/(float)sl : 0.0;
436 Rratio = (sr != 0) ? (float)cr/(float)sr : 0.0;
438 maxChildRatio = (Lratio > Rratio) ? Lratio : Rratio;
440 if ((s == 1) || (OVratio >= maxChildRatio)) return(TRUE);
441 else return(FALSE);
444 /*---------------------------------------------------------------
445 * assign_partitions (Level 2)
446 * This takes the first tree branch on the list, and assigns all of the
447 * modules therin the given partition number.
448 *---------------------------------------------------------------
450 int assign_partitions(pnum)
451 int pnum;
453 ctree *scrap = (ctree *)ipop(&c_list);
454 make_part_assignments(pnum, scrap);
456 /* save the cluster pointer for posterity */
457 parti_stats[pnum] = scrap;
461 /*---------------------------------------------------------------
462 * make_part_assignments (Level 3)
463 * recursive tree traverse, at each leaf node, it assigns the module
464 * the given partition number.
465 *---------------------------------------------------------------
467 int make_part_assignments(p, cnode)
468 int p;
469 ctree *cnode;
471 if ((int *)cnode == (int *)NULL) return; /* return (NULL); */
473 if ((cnode->left == NULL) && (cnode->right == NULL)) /*leaf node*/
475 /* set the module information for use by the boxing and string routines */
476 module_info[cnode->this->contents->index].used = p;
478 /* add the module to the appropriate partition: */
479 partitions[p] = (mlist *)concat_list(cnode->this->contents, partitions[p]);
481 else
483 make_part_assignments(p, cnode->left);
484 make_part_assignments(p, cnode->right);
487 /*---------------------------------------------------------------
488 * build_clusters (Level 2)
489 * modifies the connected mtrx, the c_list,
490 * and reassigns the cluster number(s) of any modules that are moved.
491 * this function represents one step of the clustering method, as applied
492 * to schematic modules.
493 *---------------------------------------------------------------
496 build_clusters()
498 int c_count, continueFlag = FALSE, (*acceptance_fn)();
499 clist *initClusters = NULL;
500 FILE *tfile = (debug_level < -2)?fopen("con", "a"):NULL;
502 /* Determine which of the acceptance functions should be used to pull apart the cluster
503 tree: */
505 if (debug_level < -2) /* debug info */
507 fprintf(tfile, "\n[Rule# %d] max partition size: %d, max connections: %d, ratio: %-5.3f\n",
508 partition_rule, max_partition_size, max_partition_conn, partition_ratio);
512 switch(partition_rule)
514 case 1 : acceptance_fn = (int (*)())accept_node1; break;
516 case 2 : acceptance_fn = (int (*)())accept_node2; break;
518 case 3 : acceptance_fn = (int (*)())accept_node3; break;
520 case 4 : acceptance_fn = (int (*)())accept_node4; break;
522 default: error("build_clusters - bade rule choice ");
523 break;
526 /* Setup the connection matrix */
527 build_connections(matrix_type);
528 overlay_connections(module_count, matrix_type);
529 init_clusters(module_count, &initClusters);
531 c_count = ilist_length(initClusters);
535 if (debug_level < -2) /* debug info */
537 fprintf(tfile,"Clusters to be merged correspond to rows %d & %d ", clus1, clus2);
538 p_cons(tfile, c_count, initClusters);
539 fprintf(tfile,"\n");
542 reset_connections(c_count, MIN(clus1, clus2), MAX(clus1, clus2));
543 /* Builds the <c_list> */
544 merge_clusters(clus1, clus2, c_count, &initClusters, acceptance_fn, tfile);
545 continueFlag = find_next_cluster(c_count = ilist_length(initClusters));
547 if (continueFlag == FALSE)
549 /* Nothing left is connected, so force them into partitions */
550 c_list = (clist *)append_ilist(c_list, initClusters);
551 initClusters = NULL;
552 break;
554 } while(c_count > 1);
556 if ((continueFlag == TRUE) && (initClusters != NULL) &&
557 ((initClusters->this != NULL) && ((*acceptance_fn)(initClusters->this) == TRUE)))
558 c_list = (clist *)append_ilist(c_list, initClusters);
559 else if ((initClusters != NULL) &&
560 ((initClusters->this != NULL) &&
561 ((*acceptance_fn)(initClusters->this) != TRUE)))
563 error("build_clusters: tree pruned badly.");
564 exit(-1);
567 if (debug_level < -2) fclose(tfile);
570 /*---------------------------------------------------------------
571 * init_clusters (Level 3)
572 * set up a cluster for each module, set the cluster_count, and
573 * set up the c_list, which is used to keep track of where
574 * the modules have been placed.
575 *---------------------------------------------------------------
578 init_clusters(m_count, lst)
579 int m_count;
580 clist **lst;
583 mlist *m;
584 ctree *c_leaf;
585 cluster *c_ptr;
587 /* setup the cluster list (c_list) with all of the cluster leaf nodes
588 * (Each module becomes a seperate leaf node.) Use the global module list
589 * as the information source. */
591 for (m = modules; m != NULL; m = m->next)
593 c_ptr = (cluster *)calloc(1, sizeof(cluster));
594 c_ptr->index = m->this->index;
595 c_ptr->size = 1;
596 c_ptr->connects = connected[m->this->index][m->this->index];
597 c_ptr->contents = m->this;
599 c_leaf = (ctree *)build_leaf((int *)c_ptr);
600 ipush((int *)c_leaf, (ilist **)lst);
603 /* find the two clusters that should be merged: */
604 find_next_cluster(m_count);
607 /*------------------------------------------------------------------------
608 * reset_connections (Level 3)
609 * This takes the column numbers from clus1 and clus2 and combines the two
610 * columns. The side effect of this process is to remove a column and row
611 * from the connection matrix.
612 *------------------------------------------------------------------------
614 int reset_connections(cl_count, merge_col, scratch_col)
615 int cl_count, merge_col, scratch_col;
617 int i, j;
619 for (i=0; i < cl_count - 1; i++)
621 /* first save the original merged row and scratch row, & the
622 original scratch row and scratch columns in case this merger
623 results in a new partition. If a new partition is formed, one of these
624 row/col pairs will be used to restore the connection matrix. */
625 rpl_merge_row[i] = connected[merge_col][i];
626 rpl_merge_col[i] = connected[i][merge_col];
627 rpl_scratch_row[i] = connected[scratch_col][i];
628 rpl_scratch_col[i] = connected[i][scratch_col];
630 if (i == cl_count - 2) /* need to get the full row */
632 rpl_merge_row[i+1] = connected[merge_col][i+1];
633 rpl_merge_col[i+1] = connected[i+1][merge_col];
634 rpl_scratch_row[i+1] = connected[scratch_col][i+1];
635 rpl_scratch_col[i+1] = connected[i+1][scratch_col];
638 /* Now reset the connection matrix for this set of clusters, combining clus1 & clus2: */
639 /* Note that one column and one row are dropped from the connection matrix. */
640 for (j=0; j < cl_count - 1; j++)
642 /* reset the array as if nothing were to be removed: */
643 if (i == merge_col)
645 if (j == merge_col)
646 connected[i][j] = connected[i][j] + connected[scratch_col][scratch_col]
647 - connected[i][scratch_col] - connected[scratch_col][j];
649 else if (j < scratch_col) connected[i][j] =
650 connected[i][j] + connected[scratch_col][j];
652 else connected[i][j] = connected[i][j+1] + connected[scratch_col][j+1];
655 else if (i < scratch_col)
657 if (j >= scratch_col) connected[i][j] = connected[i][j+1];
658 else if (j == merge_col) connected[i][j] =
659 connected[i][j] + connected[i][scratch_col];
661 /* else connected[i][j] = connected[i][j]; */
664 else /* (i >= scratch_col) */
666 if (j == merge_col) connected[i][j] =
667 connected[i+1][j] + connected[i+1][scratch_col];
668 else if (j < scratch_col) connected[i][j] = connected[i+1][j];
669 else connected[i][j] = connected[i+1][j+1];
676 /*---------------------------------------------------------------
677 * good_partition (Level 4)
678 * This returns TRUE iff one of the two branches of the given tree
679 * should be pruned to form a partition. The severed branch is
680 * then placed on the given cluster list (lst).
681 *---------------------------------------------------------------
683 int good_partition(tree, cCount, parts, actv, acceptance_fn, row1, row2, tf)
684 ctree **tree; /* The cluster tree in question */
685 int cCount; /* Number of clusters extant */
686 clist **parts; /* ordered list of clusters that are now partitions */
687 clist **actv; /* ordered list of actve clusters */
688 int (*acceptance_fn)(), row1, row2;
689 FILE *tf; /* Temp File - for debug information */
691 ctree *temp, *parent = *tree;
692 int r, l, p;
694 if ((int *)parent == (int *)NULL) return; /* return(NULL); */
696 r = (parent->right != NULL) ? (*acceptance_fn)(parent->right) : FALSE;
697 l = (parent->left != NULL) ? (*acceptance_fn)(parent->left) : FALSE;
698 p = (parent != NULL) ? (*acceptance_fn)(parent) : FALSE;
700 if (p == FALSE) /* clip some branch, and try again */
702 if ((l == TRUE) && /* clip the left branch */
703 ((r == FALSE) || (parent->left->this->size > parent->right->this->size)))
705 if (debug_level < -2)
707 fprintf(tf, "Cluster ");
708 print_ctree(tf, parent->left);
709 fprintf(tf,"\nWas saved as a partition #%d.(L)\n",ilist_length(*parts)+1);
712 indexed_list_insert((int *)parent->left, ilist_length(*parts),
713 (ilist **)parts);
714 if (parent->right != NULL) /* finish clipping the left branch */
716 *tree = parent->right;
717 my_free(parent);
719 else parent->left = NULL; /* now reset the parent */
720 /* replace <row1> with the old contents of <row2>: */
721 reset_connected_matrix(row1, row2, cCount, actv,
722 &rpl_scratch_col[0], &rpl_scratch_row[0], matrix_type);
723 return(TRUE);
725 else if ((r == TRUE) && /* clip the right branch */
726 ((l == FALSE) ||
727 (parent->right->this->size >= parent->left->this->size)))
729 if (debug_level < -2)
731 print_ctree(tf, parent->right);
732 fprintf(tf," being saved as a partition.(R)\n");
735 indexed_list_insert((int *)parent->right, ilist_length(*parts),
736 (ilist **)parts);
737 if (parent->left != NULL) /* finish clipping the right branch */
739 *tree = parent->left;
740 my_free(parent);
742 else parent->right = NULL;
743 /* replace <row1> with the old contents of <row1> */
744 reset_connected_matrix(row1, row1, cCount, actv,
745 &rpl_merge_col[0], &rpl_merge_row[0], matrix_type);
746 return(TRUE);
750 else return(FALSE);
753 /*---------------------------------------------------------------
754 * merge_clusters (Level 3)
755 * Take the two given column numbers, look up their corresponding clusters,
756 * and build another tree node from them. Place this node in the cluster list
757 * position indexed by c1. Remove the position indexed by c2.
758 *----------------------------------------------------------------
761 int merge_clusters(c1, c2, cCount, t, acceptance_fn, tf)
762 int c1, c2, cCount;
763 clist **t; /* Indexed list of active clusters */
764 int (*acceptance_fn)();
765 FILE *tf;
767 ctree *temp;
768 ctree *r = (ctree *)remove_indexed_element(c2, t);
769 clist *merge = (clist *)find_indexed_element(c1, *t);
770 ctree *l;
772 if (merge == NULL) {
773 error("merge_clusters: Passed bad element c1","");
774 return 0;
776 l = merge->this;
778 /* build the new treenode: */
779 /* combine the two clusters into one (clus1 and clus2) and add them to the tree: */
780 temp = (ctree *)build_node(l, r, (int *)calloc(1, sizeof(cluster)));
781 temp->this->index = c1;
782 temp->this->size = r->this->size + l->this->size;
783 temp->this->connects = connected[c1][c1];
785 /* check to see if this branch should be clipped, and saved as a partition: */
786 good_partition(&temp, cCount, &c_list, t, acceptance_fn, c1, c2, tf);
787 merge->this = temp;
790 /*---------------------------------------------------------------
791 * find_next_cluster (Level 3)
792 * keep track of which of the next clusters should be combined on the next pass:
793 * (calculate the cluster values, noting which is the smallest - then set clus1 and
794 * clus2 accordingly)
795 *----------------------------------------------------------------
797 int find_next_cluster(c_count)
798 int c_count;
800 int i, j, flag= 0;
801 float cvalue, smallest;
803 /* a hack to start off the search */
804 /* find the first two connected things : */
805 for (i=0; i < c_count; i++)
807 for (j=0; j < c_count; j++)
809 if ((j != i) && (connected[i][j] > 0))
811 smallest =
812 (float)(connected[i][i] + connected[j][j] - connected[i][j]
813 - connected[j][i])/
814 (float)(connected[i][i] + connected[j][j]);
815 clus1 = MIN(i,j);
816 clus2 = MAX(i,j);
817 i = j = flag = c_count; /* exit the loops */
821 /* check to see that smallest was set to something: */
822 if (flag == 0)
824 clus1 = 0;
825 clus2 = 1;
826 return (FALSE);
830 for (i=0; i < c_count; i++)
832 for (j=0; j < c_count; j++)
833 if ((j > i) && (connected[i][i] != 0) && (connected[j][j] != 0))
835 cvalue =
836 (float)(connected[i][i] + connected[j][j] - connected[i][j]
837 - connected[j][i]) /
838 (float)(connected[i][i] + connected[j][j]);
840 if ((smallest >= cvalue) && (connected[i][j] > 0))
842 smallest = cvalue; /* exit with clus1, clus2 set */
843 clus1 = i;
844 clus2 = j;
848 return(TRUE);
851 /*---------------------------------------------------------------
852 * internal_placement (Level 1)
853 * This places the first <partition_count> parititions
854 * These placements are on a virtual page [origin = (0,0)], and no
855 * attention is paid to modules outside of this partition.
856 * (EXCEPTION: systerminals are considered)
857 * The metric used is as follows:
858 * - All cross-coupled modules are placed in above each other
859 * - modules with systerm inputs are to the left
860 * - modules with systerm outputs are to the right
861 * - modules with a common output are placed above each other
862 * - modules with a common input are placed above each other
863 *---------------------------------------------------------------
865 /*---------------------------------------------------------------
866 * cross_coupled_p(m1, m2, l) return TRUE iff <m1> has terminals connected
867 * to both the inputs and outputs of <m2> at <l> levels of removal.
868 *--------------------------------------------------------------
870 int cross_coupled_p(m1,m2,l)
871 module *m1, *m2;
872 int l;
874 tlist *t, *tt;
875 int r1; /* The depth from <m1> to <m2> */
876 int r2; /* The depth from <m2> to <m1> */
878 for (t = m1->terms; t != NULL; t = t->next)
880 if ((t->this->type == OUT) &&
881 (r1 = on_output_net_p(m2, t->this->nt, l, 1) != FALSE))
882 /* found <m2> somewhere */
884 /* This prevents the string layer from trying to use modules that are
885 already well positioned */
886 if (m2->placed == PLACED) return; /* return(NULL); */
888 for(tt = m2->terms; tt != NULL; tt = tt->next)
890 if ((tt->this->type == OUT) &&
891 (r2 = on_output_net_p(m1, tt->this->nt, l, 1) != FALSE))
892 { /* found <m1> somewhere */
893 d1 = r1;
894 d2 = r2;
895 return(TRUE); /* return both <r1> & <r2> for non-trivial <l> */
900 return(FALSE);
902 /*---------------------------------------------------------------
903 * on_output_net_p(m, n, l) return TRUE iff <m1> has terminals connected
904 * to both the inputs and outputs of <m2> at <l>levels of removal.
905 *--------------------------------------------------------------
908 int on_output_net_p(m, n, l, s)
909 module *m;
910 net *n;
911 int l, s;
913 tlist *t, *tt;
915 /* See if the module in question is on this net */
916 for (t = n->terms; t != NULL; t = t->next)
918 if (t->this->type == IN)
920 if (t->this->mod == m) return(s); /* found something */
921 else if (l > 1) /* keep looking */
923 /* This prevents the string layer from trying to use modules that are
924 * already well positioned */
925 if (t->this->mod->placed == PLACED) return(FALSE);
927 for (tt = t->this->mod->terms; tt != NULL; tt = tt->next)
929 if ((tt->this->type == OUT) &&
930 (s = on_output_net_p(m, tt->this->nt, l-1, s+1) != FALSE))
931 return(s+1);
936 return(FALSE);
939 /*---------------------------------------------------------------
940 * better_inheritence (path1, path2, p)
941 * return TRUE if <path1> shows better inheritence then <path2>
942 *---------------------------------------------------------------
944 int better_inheritence (path1, path2, p)
945 mlist *path1, *path2;
946 int p;
948 /* <path1> shows better inheritence then <path2> if outputs of modules in
949 <path1> feed inputs of modules in <path2> that are not in <path1>. */
950 module *m, *candidateMod;
951 mlist *ml;
952 tlist *tl, *ttl;
954 for (ml = path1; ml != NULL; ml = ml->next)
956 m = ml->this;
957 for (tl = m->terms; tl != NULL; tl = tl->next)
959 if ((tl->this->type == OUT) || (tl->this->type == INOUT))
961 for(ttl = tl->this->nt->terms; ttl != NULL; ttl = ttl->next)
963 if ((ttl->this->type == IN) &&
964 (ttl->this->mod->index == m->index) && /* same partition */
965 (member_p(ttl->this->mod, path2, identity) == TRUE))
967 candidateMod = ttl->this->mod;
968 if (member_p(candidateMod, path1, identity) == FALSE)
969 return(TRUE);
975 return(FALSE);
979 /*---------------------------------------------------------------
980 * Original spl code:
981 *---------------------------------------------------------------
983 /*---------------------------------------------------------------
984 * longest_path (Level 3)
985 * For this root in the partition try to construct the
986 * longest path. If it is, use it for the string for this partition.
987 * stf addition: This is not the case if <m> is an output terminal,
988 * AND there are other items in the string [output terminals should be
989 *at the end of non-trivial strings]; AND this is not the case
990 * if <m> is not IN/INOUT terminal, AND there is some other IN/INOUT
991 * terminal along <m>'s path. [strings should begin with their input
992 * terminals, if ther are any in the string]
995 * The problem is with ties - there are (or should be) a number of
996 * modules that would make equally-long strings out of the partition,
997 * but don't make it. Some modules of equally-long strings are better
998 * than others: zb. A module that connects only to the input systerms
999 * and internally is better than one that connects to input and output
1000 * systerms .
1002 *---------------------------------------------------------------
1004 mlist *longest_path(m, p, len, cmplxLen)
1005 module *m;
1006 int p, len;
1007 int *cmplxLen;
1009 mlist *path = NULL, *x, *xprev;
1010 int cmplxPathLength = 0;
1012 reset_path_trace(partitions[p]); /* reset the flags for trace_path */
1014 /* the order of this list corresponds to the placement order within a box */
1015 path = trace_path(m, p, 0, &cmplxPathLength);
1017 if (path == NULL)
1019 *cmplxLen = 0;
1020 return(NULL);
1023 if ((cmplxPathLength > len) ||
1024 ((strings[p] != NULL) && (any_placed_p(strings[p]) == TRUE)))
1026 /* NOW- clip any systerms from the list:
1027 * (This is to see that the strings do not get oversized for modules that will
1028 * be placed outside of the partitioning scheme.)
1030 *cmplxLen = cmplxPathLength;
1031 xprev = path;
1032 for (x = path->next; x != NULL; x = x->next)
1034 if ((!strcmp(x->this->type, "OUT")) ||
1035 (!strcmp(x->this->type, "INOUT")) ||
1036 (!strcmp(x->this->type, "IN")))
1038 xprev->next = x->next;
1041 /* now check the head */
1042 if ((path->next != NULL) && ((!strcmp(path->this->type, "OUT")) ||
1043 (!strcmp(path->this->type, "INOUT")) ||
1044 (!strcmp(path->this->type, "IN"))))
1046 path = path->next;
1049 strings[p] = path;
1051 if(debug_level > 10) /* debug */
1053 fprintf(stderr,
1054 "\nNew String: Partition: %d, Root: %s\n",
1055 p, m->name);
1056 for(x = path; x != NULL; x = x->next)
1058 fprintf(stderr, "Module: %s\n", x->this->name);
1062 else *cmplxLen = len;
1063 return(strings[p]);
1066 /*---------------------------------------------------------------
1067 * longest_path_in_part
1068 *---------------------------------------------------------------
1070 mlist *longest_path_in_part(p)
1071 int p;
1073 /* return the longest path of unplaced modules in partition <p>. */
1074 mlist *bestPath = NULL, *path, *ml;
1075 int len, connCount, bestLen = 0;
1077 for (ml = partitions[p]; ml != NULL; ml = ml->next)
1079 // if (ml->this->placed == FALSE)
1080 if (ml->this->placed == UNPLACED)
1082 path = longest_path(ml->this, p, bestLen, &len);
1083 if (len > bestLen)
1085 bestLen = len;
1086 bestPath = path;
1087 connCount = count_connections(bestPath, p);
1089 else if ((len == bestLen) &&
1090 (count_connections(path, p) > connCount))
1092 bestLen = len;
1093 bestPath = path;
1094 connCount = count_connections(bestPath, p);
1096 else if ((len == bestLen) &&
1097 (better_inheritence(path, bestPath, p) == TRUE))
1099 bestLen = len;
1100 bestPath = path;
1101 connCount = count_connections(bestPath, p);
1105 strings[p] = bestPath;
1106 str_length[p] = 0;
1107 str_height[p] = 0;
1108 return(bestPath);
1111 /* ---------------------------------------------------------------------------*/
1112 void insert_boxtile(t, w)
1113 tile *t;
1114 mlist *w;
1116 mlist *ml;
1117 /* Mark where the new tile went: */
1118 for(ml = w; ml != NULL; ml = ml->next) ml->this->htile = t;
1119 t->this = (int *)w;
1121 /* ---------------------------------------------------------------------------*/
1122 void manage_string_contents_for_merge(newTile, oldTile)
1123 tile *newTile, *oldTile;
1125 mlist *ml;
1126 /* Mark where the new tile went: */
1127 for(ml = (mlist *)oldTile->this; ml != NULL; ml = ml->next)
1128 ml->this->htile = newTile;
1129 newTile->this = oldTile->this;
1131 /*---------------------------------------------------------------
1132 * place_first_strings (Level 1)
1133 * This places the non-zero strings. (whatever's in strings[])
1134 * We assume there is only one of them per partition.
1135 *---------------------------------------------------------------
1137 void place_first_strings()
1139 int i, start_x, start_y;
1140 tile *boxTile;
1142 xfloor = 0; /* initialize the offsets for the placement routines */
1143 yfloor = 0;
1145 /* Set the content-managing functions for this tilespace: */
1146 insert_contents = insert_boxtile;
1147 manage_contents__hmerge = manage_string_contents_for_merge;
1148 manage_contents__vmerge = manage_string_contents_for_merge;
1150 for (i = 1; i <= partition_count; i++)
1152 if (partitions[i] != NULL)
1154 init_string(i);
1156 place_head(i);
1158 start_x = strings[i]->this->x_pos + strings[i]->this->x_size +
1159 WHITE_SPACE * count_terms(strings[i]->this, RIGHT);
1160 start_y = strings[i]->this->y_pos + strings[i]->this->y_size;
1162 place_string(i);
1164 if (yfloor < 0) fixup_string(i, xfloor, yfloor - 1);
1166 x_sizes[i] = str_length[i];
1167 y_sizes[i] = str_height[i];
1169 boxTile = insert_tile(rootTiles[i], 0, 0, str_length[i], str_height[i],
1170 strings[i]);
1174 /*---------------------------------------------------------------
1175 * init_string (Level 2)
1176 * Look through the partitions, identifying which modules which are roots.
1177 * Find the longest path from any root in each partition, make this the
1178 * (single) non-trivial string for that partition.
1179 *---------------------------------------------------------------
1181 init_string(p)
1182 int p;
1184 mlist *ml;
1185 int len = 0;
1187 /* lookup the actual module */
1188 for (ml = partitions[p]; ml != NULL; ml = ml->next)
1190 /* if it is a root, see if it is the head of the longest
1191 * possible path within its own partition.
1193 if (is_root(ml->this, ml->this->index))
1195 longest_path(ml->this, p, len, &len);
1198 if (strings[p] == NULL) longest_path(partitions[p]->this, p, len, &len);
1201 /*---------------------------------------------------------------
1202 * place_head (Level 2)
1203 * perform the rotation and placement of head of the strings
1204 * Note we actually do the rotation math here, since
1205 * we should only have to do it once. If we ever do
1206 * hierarical rotation, we might just want to keep the fact
1207 * that it was rotated.
1208 *---------------------------------------------------------------
1210 int place_head(part)
1211 int part;
1213 mlist *ml;
1214 module *m;
1215 int rot = 0;
1217 if (strings[part] == NULL) return(0);
1219 ml = strings[part];
1220 m = ml->this;
1222 /* For analog devices, m may not have a primary output */
1224 if ((ml->next != NULL) && (m->primary_out != NULL)) {
1226 /* non-singular string */
1227 switch (side_of(m->primary_out)) {
1229 /* rotate module to PUT PRIMARY OUTPUT ON THE RIGHT */
1231 case LEFT: rot = ONE_EIGHTY; break;
1232 case UP: rot = NINETY; break;
1233 case RIGHT: rot = ZERO; break;
1234 case DOWN: rot = TWO_SEVENTY; break;
1236 default: error("place_head: bad side_of primary terminal",
1237 m->name);
1239 if (rot != ZERO)
1240 {/* update all the terminal postions and sides */
1242 rotate_module(m, rot);
1245 m->x_pos = WHITE_SPACE * count_terms(m, LEFT);
1246 m->y_pos = WHITE_SPACE * count_terms(m, DOWN) + 1;
1248 /* Create the fuzzy (delayed-evaluation) position: */
1249 m->fx->item1 = create_rng_varStruct
1250 (create_srange(m->x_pos - XFUZZ, m->x_pos + XFUZZ, X));
1251 m->fy->item1 = create_rng_varStruct
1252 (create_srange(m->y_pos - YFUZZ, m->y_pos + YFUZZ, Y));
1254 /* mark the module as placed */
1255 m->placed = PLACED;
1257 str_length[part] = m->x_pos + m->x_size + /* CHANNEL_LENGTH + */
1258 (WHITE_SPACE * (count_terms(m, RIGHT) + 1));
1259 str_height[part] = m->y_pos + m->y_size + /* CHANNEL_HEIGHT + */
1260 (WHITE_SPACE * (count_terms(m, UP) + 1));
1263 /*------------------------------------------------------------------------------------
1264 * output_term_connecting (Level 3)
1265 * Locate the first terminal that is an output of <m1> that ties to <m2>:
1266 *------------------------------------------------------------------------------------
1268 term *output_term_connecting(m1, m2)
1269 module *m1, *m2;
1271 term *t;
1272 tlist *tl, *tll;
1274 if (m1 == NULL) return(NULL);
1275 else if (m2 == NULL) return(m1->primary_out);
1277 for (tl = m1->terms; tl != NULL; tl = tl->next)
1279 if ((tl->this->type == OUT) || (tl->this->type == INOUT))
1281 t = tl->this;
1282 for (tll = m2->terms; tll != NULL; tll = tll->next)
1284 if (t->nt == tll->this->nt) return(t);
1288 /* Default : (Probably will cause problems... */
1289 return(m1->primary_out);
1293 /*---------------------------------------------------------------
1294 * place_string (Level 2)
1295 * perform the rotation and placement of the rest of each string
1296 * return the value of the lowest module's y postion.
1297 * This monster is very convoluted, and difficult to explain, mainly
1298 * due to the complexities of complex-string placement.
1299 *---------------------------------------------------------------
1301 int place_string(part)
1302 int part;
1304 mlist *ml, *t, *given_string, *top_string = NULL;
1305 module *m, *cc_m, *last_m, *top_cc_mod = NULL, *bot_cc_mod = NULL;
1306 term *prevt;
1307 int tsLength, lev, margin, rot = 0, cc_flag = FALSE, curHeight;
1308 int offset = 0;
1310 if (strings[part] == NULL) return(0);
1312 given_string = strings[part];
1313 last_m = given_string->this;
1314 prevt = output_term_connecting(last_m, (given_string->next != NULL) ? given_string->next->this : NULL);
1316 /* skip the first one, we just did it in init_place above */
1318 for(ml = given_string->next; ml != NULL; ml = ml->next)
1320 m = cc_m = ml->this;
1321 if (m->placed == UNPLACED)
1324 /* Set up all the strangeness for cross-coupled modules: */
1325 for (lev = 1; (lev <= cc_search_level) && (cc_m != NULL); lev++)
1327 if (cross_coupled_p(last_m, cc_m, lev) != FALSE)
1329 /* <d1> & <d2> (which represent the depths from <last_m> to <m> & vv)
1330 * are now set */
1331 cc_flag = TRUE;
1332 top_cc_mod = last_m;
1333 bot_cc_mod = cc_m;
1334 break;
1336 cc_m = (ml->next != NULL) ? ml->next->this : NULL;
1339 /* This creates two modes to operate in: either cc mode, or in-line mode, all centered
1340 around the <cc_flag>. Very strange contortions happen for multi-level cc modules.
1341 <lev> is the level of removal from <last_m> at which the cross-coupling was discovered
1342 <cc_m> is the module that is coupled to <last_m> (AKA <bot_cc_mod>).
1343 <last_m> is the last module to be succesfully placed from string<ml>
1344 (AKA <top_cc_mod>).
1346 <m> is the next module to be placed behind <last_m>, and all modules between <m> &
1347 <cc_m> belong behind <last_m>.
1348 Any modules remaining in string<ml> (behind <cc_m>) belong behind <cc_m>. <cc_m>
1349 should be placed directly beneath <last_m>.
1353 /* Analog devices do not necessarily have a primary input */
1355 if (m->primary_in != NULL) {
1356 switch (side_of(m->primary_in)) {
1357 /* rotate module to put PRIMARY INPUT ON THE LEFT */
1359 case LEFT: rot = ZERO; break;
1360 case UP: rot = TWO_SEVENTY; break;
1361 case RIGHT: rot = ONE_EIGHTY; break;
1362 case DOWN: rot = NINETY; break;
1364 default: error("place_string: bad side_of primary terminal",
1365 m->name);
1368 /* update all the terminal postions and sides */
1369 if (rot != ZERO) rotate_module(m, rot);
1371 /* move the module to the right of the space already allocated.
1372 NOTE: At this point the function becomes recursive, so as to handle the
1373 top string completely. There is a top string to be handled iff a
1374 pair of cc modules has been discovered, AND we are about to place
1375 the bottom module. */
1377 if ((cc_flag == TRUE) && (m == bot_cc_mod))
1379 /* mark <bot_cc_mod> as PLACED, so path_trace() will not step on him. */
1380 bot_cc_mod->placed = PLACED;
1381 top_cc_mod->placed = UNPLACED; /* This is so trace_path() will work properly */
1382 set_flag_value(partitions[part], UNSEEN);
1383 set_flag_value(ml, SEEN);
1384 given_string = strings[part];
1386 /* reset strings[part] with the top-string info: */
1387 top_string = longest_path(top_cc_mod, part, 0, &tsLength);
1388 top_cc_mod->placed = PLACED; /* it really is placed, so note it. */
1390 if ((top_string != NULL) && (top_string->next != NULL))
1392 offset = place_string(part);
1393 /* add the modules in <given_string> back to stings[part] */
1394 for(t = given_string; t != NULL; t = t->next)
1396 pushnew(t->this, &strings[part]);
1399 else strings[part] = given_string; /* restore strings[part] */
1401 /* now that the top string has been handled, finish up with the bottom
1402 string: */
1403 m->x_pos = top_cc_mod->x_pos;
1404 m->y_pos = top_cc_mod->y_pos - m->y_size - CC_SPACE -
1405 (WHITE_SPACE * (count_terms(m, DOWN) + 1)) + offset;
1407 /* Create the fuzzy (delayed-evaluation) position: */
1408 m->fx->item1 = create_var_varStruct(top_cc_mod->fx);
1409 /* Short version (not quite right) */
1410 m->fy->item1 = create_rng_varStruct
1411 (create_srange(m->y_pos - YFUZZ,
1412 m->y_pos + YFUZZ, Y));
1416 else
1418 margin = WHITE_SPACE * (count_terms_between_mods(last_m, m) + 1);
1419 m->x_pos = last_m->x_pos + last_m->x_size + margin;
1420 m->y_pos = line_up_mod(m, prevt);
1422 /* Create the fuzzy (delayed-evaluation) position: */
1423 /* fx = last_m->x_pos + last_m->x_size + margin +/- XFUZZ */
1424 m->fx->item1 =
1425 create_var_struct
1426 (ADD, last_m->fx,
1427 create_var_struct
1428 (ADD, create_int_varStruct(&last_m->x_size),
1429 create_rng_varStruct
1430 (create_srange(margin - XFUZZ, margin + XFUZZ, X))));
1431 /* Short version (not quite right) */
1432 m->fy->item1 =
1433 create_rng_varStruct(create_srange(m->y_pos - YFUZZ,
1434 m->y_pos + YFUZZ, Y));
1437 /* mark the module as placed */
1438 m->placed = PLACED;
1440 /* but we might have gone below the bottom, remember it */
1441 offset = (bot_cc_mod != NULL) ?
1442 bot_cc_mod->y_pos - (WHITE_SPACE * count_terms(bot_cc_mod, DOWN)) : 0;
1443 yfloor = MIN(yfloor, (m->y_pos - (WHITE_SPACE * count_terms(m, DOWN))));
1445 /* We might have gone above the current top */
1446 curHeight = m->y_pos + m->y_size + CHANNEL_HEIGHT +
1447 (WHITE_SPACE * (count_terms(m, UP) + 1));
1448 str_height[part] = MAX(curHeight, str_height[part]);
1450 str_length[part] = MAX(str_length[part],
1451 m->x_pos + m->x_size + CHANNEL_LENGTH +
1452 (WHITE_SPACE * (count_terms(m, RIGHT) + 1)));
1455 /* get ready for the next iteration */
1456 prevt = output_term_connecting(m, (ml->next != NULL) ? ml->next->this : NULL);
1457 last_m = m;
1460 return(offset);
1464 /*---------------------------------------------------------------
1465 * box_placement (Level 1)
1466 * should follow module_placement()
1467 *---------------------------------------------------------------
1470 void box_placement()
1472 int i, len, start_x, start_y;
1473 module *mod;
1474 mlist *box;
1476 /* for each partition, find the next string. Then place this string within its box.
1477 * Then place this box around the other boxes (the PLACED modules within the given
1478 * partition)
1481 /* remove old connection counts */
1482 reset_info();
1484 /* initialize lower left corner offset */
1485 xfloor = 0;
1486 yfloor = 0;
1488 for(i = 1; i <= partition_count;i++)
1490 mod = select_next_box(i); /* NOT IN USE yields a mod not already placed */
1492 while (mod != NULL)
1494 box = longest_path_in_part(i);
1495 /*NEW box = longest_path(mod, i, 0, &len); /* find the next string */
1496 place_head(i); /* place the first module in the box */
1497 /* box == strings[i] */
1498 /* Added by Tim to cope with a segfault */
1499 if (strings[i] == NULL) {
1500 error("box_placement: NULL strings entry", "");
1501 break;
1503 start_x = strings[i]->this->x_pos + strings[i]->this->x_size +
1504 WHITE_SPACE * count_terms(strings[i]->this, RIGHT);
1505 start_y = strings[i]->this->y_pos;
1506 place_string(i); /* place the rest of the string */
1507 if( yfloor < 0) fixup_string(i, xfloor, yfloor - 1);
1509 /* move the box to its position about the boxes already placed in the
1510 partition */
1511 box = strings[i]; /* Pick up anything added in "place_string" */
1512 place_box(box, i);
1513 mod = select_next_box(i);
1517 /*---------------------------------------------------------------
1518 * old_select_next_box (Level 2)
1519 *---------------------------------------------------------------
1521 module *old_select_next_box(part)
1522 int part;
1524 /* Select the "most connected" unplaced module within the partition */
1525 mlist *ml;
1526 module *mod, *best = NULL;
1528 int ci = -1;
1530 for(ml = partitions[part]; ml != NULL; ml = ml->next)
1532 mod = ml->this;
1534 /* re-count connections just for this module */
1535 count_inout(mod->index, part);
1537 if ((mod->placed == UNPLACED) && /* skip things already down */
1538 (module_info[mod->index].in > ci) &&
1539 (strcmp(mod->type, "OUT")) && /* skip systerms */
1540 (strcmp(mod->type, "INOUT")) &&
1541 (strcmp(mod->type, "IN")))
1543 ci = module_info[mod->index].in;
1544 best = mod;
1547 return(best);
1549 /*---------------------------------------------------------------
1550 * select_next_box (Level 2)
1551 * This determines the order that modules are placed within a partition.
1552 *---------------------------------------------------------------
1554 module *select_next_box(part)
1555 int part;
1557 /* Select the module in the partition that is best connected to the
1558 already-placed modules within the partition. */
1559 mlist *ml, *mll;
1560 module *mod, *best = NULL;
1561 int count, bestCount = 0;
1563 for(ml = partitions[part]; ml != NULL; ml = ml->next)
1565 mod = ml->this;
1566 if ((mod->placed == UNPLACED) && /* skip things already down */
1567 (strcmp(mod->type, "OUT")) && /* skip systerms */
1568 (strcmp(mod->type, "INOUT")) &&
1569 (strcmp(mod->type, "IN")))
1571 count = 0;
1572 for(mll = partitions[part]; mll != NULL; mll = mll->next)
1574 if (mll->this->placed == PLACED)
1575 count += connected[mod->index][mll->this->index];
1577 if (count > bestCount)
1579 bestCount = count;
1580 best = mod;
1584 if (best == NULL) return(old_select_next_box(part));
1585 return(best);
1587 /*---------------------------------------------------------------
1588 * default_place_box(Level 2)
1589 * what to do when there is no connectivity information: set x, y
1590 * to have this box abut the current partition:
1591 *---------------------------------------------------------------
1593 default_place_box(box, part, x, y)
1594 mlist *box;
1595 int part, *x, *y;
1597 int side;
1599 /* decide which side of the bounding box to add this part onto */
1600 /* NOTE: The call to "best_side_box" also sets the side/count globals,
1601 including their signs. */
1603 side = best_side_box(part, box);
1605 switch(side)
1607 case LEFT:
1609 *x = xfloor - str_length[part];
1610 *y = (int)(ygbr - ygr);
1611 break;
1613 case UP:
1615 *x = (int)(xgbr - xgr) - xfloor;
1616 *y = y_sizes[part];
1617 break;
1619 case RIGHT:
1621 *x = x_sizes[part];
1622 *y = (int)(ygbr - ygr);
1623 break;
1625 case DOWN:
1627 *x = (int)(xgbr - xgr) - xfloor;
1628 *y = yfloor - str_height[part];
1629 break;
1633 /*-------------------------------------------------------------------------
1634 * Pivot and anchor determination: For left and right-cominated movement,
1635 * the pivots and anchors need to be set on the edge of a filled tile, so
1636 * that any desired lineup can occur. This is deemed unneccessary for
1637 * up- and downward movement.
1639 * NOTE: set_pivot differs from det_pivot_point in that set_pivot does not
1640 * have a tile space to work in, rather simply the dimensions of the
1641 * tile that will contain the pivot point.
1642 *-------------------------------------------------------------------------*/
1643 det_anchor_points(root, xCount, yCount, gravX, gravY, anchX, anchY)
1644 tile *root;
1645 int xCount, yCount, gravX, gravY;
1646 int *anchX, *anchY;
1648 /* set the anchor point */
1649 tile *tt, *t = locate(root, gravX, gravY);
1651 if (t == NULL)
1653 /* Just use the gravity points, as calculated. */
1654 *anchX = gravX;
1655 *anchY = gravY;
1657 else if ((abs(yCount) > abs(xCount)) || (xCount == 0))
1659 /* Just use the gravity points, as calculated. */
1660 *anchX = gravX;
1661 *anchY = gravY;
1663 else
1665 /* find the appropriate edge of the tile space: */
1666 if (xCount > 0) /* right movement, so the anchor goes on the right edge */
1668 *anchY = gravY;
1669 *anchX = (t->this == NULL) ? gravX : t->x_pos + t->x_len;
1670 /* The piv/anchor points should be on the egde of a filled tile, not between
1671 filled tiles */
1672 tt = locate(t, *anchX + 1, *anchY);
1673 if ((tt != NULL) && (tt->this != NULL))
1674 fprintf(stderr, "bad anchor chosen for part @(%d, %d)\n", *anchX, *anchY);
1676 else /* left movement, so the anchor goes on the left edge. */
1678 *anchY = gravY;
1679 *anchX = (t->this == NULL) ? gravX : t->x_pos;
1680 /* The piv/anchor points should be on the egde of a filled tile, not between
1681 filled tiles */
1682 tt = locate(t, *anchX - 1, *anchY);
1683 if ((tt != NULL) && (tt->this != NULL))
1684 fprintf(stderr, "bad anchor chosen for part @(%d, %d)\n", *anchX, *anchY);
1689 /*-------------------------------------------------------------------------*/
1690 int horizontally(m1, m2)
1691 module *m1, *m2;
1693 if (m1->x_pos <= m2->x_pos) return(TRUE);
1694 else return(FALSE);
1696 /*-------------------------------------------------------------------------*/
1697 int vertically(m1, m2)
1698 module *m1, *m2;
1700 if (m1->y_pos <= m2->y_pos) return(TRUE);
1701 else return(FALSE);
1703 /*-------------------------------------------------------------------------*/
1704 det_pivot_points(root, xCount, yCount, gravX, gravY, p, pivX, pivY)
1705 tile *root;
1706 int xCount, yCount, gravX, gravY;
1707 int p; /* partition number */
1708 int *pivX, *pivY;
1710 /* set the pivot point */
1711 tile *tt, *t = locate(root, gravX, gravY);
1712 int offsetX = 0, offsetY = 0;
1714 /* all modules in the partition need to be offset by the difference between the
1715 LLH Module's location and (0,0). This accounts for differences between the
1716 tile spaces, and should not be a large number. This is most critical for
1717 small partitions. */
1719 if ((t == NULL) || (abs(yCount) > abs(xCount)) || (xCount == 0))
1721 /* Just use the gravity points, as calculated along with the desired offsets: */
1722 *pivX = gravX + offsetX;
1723 *pivY = gravY + offsetY;
1725 else
1727 /* find the appropriate edge of the tile space: */
1728 if (xCount < 0) /* left movement, so the pivot goes on the right edge */
1730 *pivY = gravY + offsetY;
1731 *pivX = (t->this == NULL) ? gravX : t->x_pos + t->x_len;
1732 tt = locate(t, *pivX + 1, *pivY);
1733 /* The piv/anchor points should be on the edge of a filled tile, not between
1734 filled tiles */
1735 if ((tt != NULL) && (tt->this != NULL))
1736 fprintf(stderr, "bad pivot chosen for partition @(%d, %d)\n", *pivX, *pivY);
1738 else /* right movement, so the pivot goes on the left edge. */
1740 *pivY = gravY + offsetY;
1741 *pivX = (t->this == NULL) ? gravX : t->x_pos;
1742 /* The piv/anchor points should be on the egde of a filled tile, not between
1743 filled tiles */
1744 tt = locate(t, *pivX - 1, *pivY);
1745 if ((tt != NULL) && (tt->this != NULL))
1746 fprintf(stderr, "bad pivot chosen for partition @(%d, %d)\n", *pivX, *pivY);
1750 /*-------------------------------------------------------------------------*/
1751 set_pivot(xLen, yLen, xCount, yCount, gravX, gravY, pivX, pivY)
1752 int xLen, yLen, xCount, yCount, gravX, gravY;
1753 int *pivX, *pivY;
1756 /* set the pivot point */
1758 if ((abs(yCount) > abs(xCount)) || (xCount == 0))
1760 /* Just use the gravity points, as calculated. */
1761 *pivX = gravX;
1762 *pivY = gravY;
1764 else
1766 /* find the appropriate edge of the tile space: */
1767 if (xCount < 0) /* left movement, so the pivot goes on the right edge */
1769 *pivY = gravY;
1770 *pivX = xLen;
1772 else /* right movement, so the pivot goes on the left edge. */
1774 *pivY = gravY;
1775 *pivX = 0; /* default origin */
1781 /*-------------------------------------------------------------------------*/
1782 normalize_side_counts(xCount,yCount)
1783 int *xCount, *yCount;
1785 /* Normalize the count values. This is only important if one of them is 0. */
1786 if (*xCount == 0) *yCount = *yCount/abs(*yCount);
1787 else if (*yCount == 0) *xCount = *xCount/abs(*xCount);
1790 /*-------------------------------------------------------------------------*/
1793 /*---------------------------------------------------------------
1794 * place_box(Level 2)
1796 *---------------------------------------------------------------
1798 place_box(box, part)
1799 mlist *box;
1800 int part;
1802 tile *boxTile;
1803 int side, loc, anchX, anchY, pivX, pivY;
1804 int x, y;
1806 /* decide which side of the bounding box to add this part onto */
1807 /* NOTE: The call to "best_side_box" also sets the side/count globals,
1808 including their signs. */
1810 side = best_side_box(part, box);
1812 if ((xSideCount == 0) && (ySideCount == 0))
1814 default_place_box(box, part, &x, &y);
1815 boxTile = insert_tile(rootTiles[part], x, y, str_length[part],
1816 str_height[part], box);
1818 else
1820 det_anchor_points(rootTiles[part], xSideCount, ySideCount,
1821 (int)xgbr, (int)ygbr, &anchX, &anchY);
1822 set_pivot(str_length[part], str_height[part], xSideCount, ySideCount,
1823 (int)xgr, (int)ygr, &pivX, &pivY);
1824 normalize_side_counts(&xSideCount, &ySideCount);
1827 boxTile = angled_tile_insertion(rootTiles[part],
1828 anchX, anchY, /* Anchor point */
1829 xSideCount, ySideCount, /* Slope of axis of motion */
1830 pivX, pivY, /* Pivot point (in new tile)*/
1831 str_length[part], str_height[part], /* tile size */
1832 box);
1835 if (boxTile == NULL) /* This shouldn't happen */
1837 error("place_box: No valid insertion found!!","");
1838 exit(1);
1841 x = boxTile->x_pos;
1842 y = boxTile->y_pos;
1844 move_string(part, x, y);
1846 /* adjust the bounding box, based on the new partition configuration: */
1847 boxTile = best_tile_in_space(rootTiles[part], most_left);
1848 xfloor = boxTile->x_pos;
1850 boxTile = best_tile_in_space(rootTiles[part], most_down);
1851 yfloor = boxTile->y_pos;
1853 boxTile = best_tile_in_space(rootTiles[part], most_right);
1854 x_sizes[part] = boxTile->x_pos + boxTile->x_len;
1856 boxTile = best_tile_in_space(rootTiles[part], most_up);
1857 y_sizes[part] = boxTile->y_pos + boxTile->y_len;
1859 /* put the lower left corner of the string back at 0,0 */
1860 if((xfloor < 0)||(yfloor < 0)) fixup_partition(part, xfloor, yfloor);
1864 /*---------------------------------------------------------------
1865 * placement_prep (Level 1)
1866 * Do the prep work for placing the partitions...
1867 *---------------------------------------------------------------
1869 void placement_prep()
1871 /* reset offset */
1872 xfloor = 0;
1873 yfloor = 0;
1875 /* Start by removing the system terminals, and building a connection matrix that
1876 * will allow all of the internal modules to be placed. Place them, and then go
1877 * back to handle the two new partitions (partition_count + 1 and partition_count + 2)
1878 * that have not been accounted for as of yet. Finally, these two new paritions will
1879 * need to be placed.
1881 initialize_partition_markings(partition_count);
1882 erase_systerms();
1883 /* convert_boxes_to_module_sets(partition_count); */
1884 build_connections_amongst_partitions(partition_count, UNSIGNED);
1886 /* UNSIGNED used to be matrix_type */
1889 /*---------------------------------------------------------------
1890 * partition_placement (Level 1)
1891 * Put all the partitions into one bounding box in partition 0,
1892 * based on picking the largest number of connections off the diagonal
1893 * of the connection matrix; (which has been built to match the
1894 * partitions, seen as clusters)
1895 *---------------------------------------------------------------
1897 mlist *partition_placement()
1899 int tx,ty;
1900 ilist *part_map = NULL;
1901 int next, c_count, i, *part, order = 1;
1902 FILE *tfile = (debug_level < -1)?fopen("con", "a"):NULL;
1904 if (debug_level < -1) /* debug info */
1906 fprintf(tfile, "\n-----?? [Rule# %d] -----------------------------------\n",
1907 partition_rule);
1910 /* initialize the mapping from partition number to the column within the
1911 connection matrix: */
1913 for (i = 1; i <= partition_count; i++)
1915 /* unmark all of the modules, as none have been added to partition[0]: */
1916 set_flag_value(partitions[i], UNPLACED);
1918 /* continue setting up the cluster-matrix to partition number mapping: */
1919 part = (int *)calloc(1, sizeof (int));
1920 *part = i;
1922 /* Partitions are numbered [1..partition_count], the array is
1923 [0..partition_count] */
1924 indexed_list_insert(part, i ,&part_map);
1927 /* Pick the next partition to go down, and place it in partition[0]:
1928 * NOTE: this is the only time that <next> corresponds directly to the actual partition
1929 * number being placed.
1931 c_count = partition_count;
1932 next = find_max_diagonal(c_count);
1934 while (c_count >= 1)
1936 if (next == 0) /* couldn't find anything */
1938 next = 1; /* Take the next partition in the part_map */
1941 part = remove_indexed_element(next, &part_map);
1943 if (debug_level < -1) /* debug info */
1945 fprintf(tfile,"merging P0 and P%d", *part);
1946 p_cons(tfile, c_count+1, NULL);
1947 fprintf(tfile,"\n");
1950 place_partition(*part, order++);
1951 reset_connections(c_count+1, 0, next);
1952 next = find_max_connections_to_P0(--c_count);
1955 if (debug_level < -1) fclose(tfile);
1957 /* cleanup */
1959 /* put the lower left corner of the box back at 0,0 */
1960 if((xfloor < 0)||(yfloor < 0))
1962 reset_borders(xfloor,yfloor);
1963 fixup_partition(0, xfloor, yfloor);
1966 build_connections(matrix_type); /* rebuild the connection table for modules */
1968 return(partitions[0]);
1970 /*===================================================================================*/
1971 /*---------------------------------------------------------------
1972 * initialize_partition_markings (Level 2)
1973 * This unmarks the ->placed field for all modules, so the gravity_
1974 * partition() will work properly.
1975 *--------------------------------------------------------------
1977 initialize_partition_markings(pc)
1978 int pc;
1980 mlist *ml;
1981 int i;
1982 for(i = 1; i <= pc; i++)
1984 for (ml = partitions[i]; ml != NULL; ml = ml->next)
1986 ml->this->flag = UNPLACED;
1990 /*----------------------------------------------------------------------------*/
1991 provide_module_spacing(m, xPos, yPos, xLen, yLen)
1992 module *m;
1993 int *xPos, *yPos, *xLen, *yLen;
1995 int leftSpacing = (WHITE_SPACE * count_terms(m, LEFT));
1996 int rightSpacing = (WHITE_SPACE * count_terms(m, RIGHT));
1997 int topSpacing = (WHITE_SPACE * count_terms(m, UP));
1999 switch(validate(m->type))
2001 case BUFFER :
2002 case NOT_ :
2003 case AND :
2004 case NAND :
2005 case OR :
2006 case NOR :
2007 case XOR :
2008 case XNOR : *xPos = m->x_pos - leftSpacing;
2009 *yPos = m->y_pos - WHITE_SPACE;
2010 *xLen = m->x_size + rightSpacing + leftSpacing;
2011 *yLen = m->y_size + WHITE_SPACE * 2;
2012 break;
2013 case INPUT_SYM :
2014 case OUTPUT_SYM : *xPos = m->x_pos;
2015 *yPos = m->y_pos;
2016 *xLen = m->x_size = rightSpacing;
2017 *yLen = m->y_size;
2018 break;
2019 case BLOCK :
2020 default :
2021 *xPos = m->x_pos - leftSpacing;
2022 *yPos = m->y_pos - WHITE_SPACE;
2023 *xLen = m->x_size + leftSpacing + rightSpacing;
2024 *yLen = m->y_size + topSpacing + 2 * WHITE_SPACE;
2025 break;
2028 /*===================================================================================*/
2029 /*---------------------------------------------------------------
2030 * convert_boxes_to_module_sets (Level 2)
2031 * This converts the tiles from representing strings to representing modules.
2032 *--------------------------------------------------------------
2034 convert_boxes_to_module_sets(pc)
2035 int pc;
2037 module *m;
2038 mlist *string, *ml;
2039 tile *t;
2040 tilist *tl, *boxes = NULL;
2041 int i, x, y, xSize, ySize;
2043 for(i = 1; i <= pc; i++)
2045 boxes = nonFreespace(rootTiles[i], &boxes);
2046 for (tl = boxes; tl != NULL; tl = tl->next)
2048 string = (mlist *)tl->this->this; /* the string is the tile contents */
2050 rootTiles[i] = delete_tile(tl->this); /* scrap the big tile */
2052 for(ml = string; ml != NULL; ml = ml->next)
2054 /* Insert the small tiles: NOTE: THE SPACING IS INCORRECT!! */
2055 m = ml->this;
2056 provide_module_spacing (m, &x, &y, &xSize, &ySize);
2057 insert_tile(rootTiles[i], x, y, xSize, ySize, m);
2060 boxes = (tilist *)free_list(boxes);
2063 /*===================================================================================*/
2064 /*---------------------------------------------------------------
2065 * erase_syterms (Level 2)
2066 * The systerm modules have been placed within the various partitions.
2067 * remove them from their partitions so that they may be placed seperately
2068 * along the edges of the diagram. These are broken into two groups,
2069 * the INs and the OUTs.
2071 * NOTE: This also removes the terminals from the nets.
2073 *---------------------------------------------------------------
2075 erase_systerms()
2077 int p = partition_count, old_part; /* number of partitions */
2078 mlist *systerm;
2079 int ins = p + 2, outs = p + 1;
2081 for (systerm = ext_mods; systerm != NULL; systerm = systerm->next)
2083 systerm->this->placed = UNPLACED; /* unplace the module */
2084 old_part = module_info[systerm->this->index].used;
2086 if (!strcmp(systerm->this->type, "OUT"))
2088 rem_item(systerm->this, &partitions[old_part]);
2089 module_info[systerm->this->index].used = outs;
2090 partitions[outs] = (mlist *)concat_list(systerm->this, partitions[outs]);
2092 else /*( (!strcmp(systerm->this->type, "IN")) ||
2093 (!strcmp(systerm->this->type, "INOUT")) ) */
2095 rem_item(systerm->this, &partitions[old_part]);
2096 module_info[systerm->this->index].used = ins;
2097 partitions[ins] = (mlist *)concat_list(systerm->this, partitions[ins]);
2101 /* NOTE: the global <partition_count> is not updated -
2102 <partition_count> + 1 refers to the output terminals, and
2103 <partition_count> + 2 indexes the input/inout terminals. */
2107 /*---------------------------------------------------------------
2108 * default_place_partition (Level 2)
2109 * Put a partition down along an edge of partition[0].
2110 *---------------------------------------------------------------
2112 default_place_partition(part, x, y)
2113 int part, *x, *y;
2115 /* Unangled, straight-up adjacent placement. All this does is to calculate where
2116 the partition's new origin should be placed at. */
2117 int side;
2119 if(partitions[0] == NULL)
2121 /* this is the first partition to be placed */
2122 *x = 0;
2123 *y = 0;
2125 else
2127 if (partitions[part] == NULL) return; /* return()NULL); */
2129 /* decide which side of the bounding box to add this partition onto */
2130 side = best_side_part(part);
2132 switch(side)
2134 case LEFT:
2136 *x = xfloor - (x_sizes[part] + CHANNEL_LENGTH +
2137 WHITE_SPACE * count_terms_part(part, RIGHT));
2138 *y = (int)(ygbr - ygr);
2139 break;
2141 case UP:
2143 *x = (int)(xgbr - xgr);
2144 *y = y_sizes[0] + CHANNEL_HEIGHT +
2145 WHITE_SPACE * count_terms_part(part, DOWN);
2146 break;
2148 case RIGHT:
2150 *x = x_sizes[0] + CHANNEL_LENGTH +
2151 WHITE_SPACE * count_terms_part(part, LEFT);
2152 *y = (int)(ygbr - ygr);
2153 break;
2155 case DOWN:
2157 *x = (int)(xgbr - xgr);
2158 *y = yfloor - (y_sizes[part] + CHANNEL_HEIGHT +
2159 WHITE_SPACE * count_terms_part(part, UP));
2160 break;
2165 /* ---------------------------------------------------------------------------*/
2166 void insert_boxtile_for_partitions(t, w)
2167 tile *t;
2168 mlist *w;
2170 mlist *ml;
2171 /* Mark where the new tile went: */
2172 for(ml = w; ml != NULL; ml = ml->next) ml->this->vtile = t;
2173 t->this = (int *)w;
2175 /* ---------------------------------------------------------------------------*/
2176 void manage_partition_contents_for_merge(newTile, oldTile)
2177 tile *newTile, *oldTile;
2179 mlist *ml;
2180 /* Mark where the new tile went: */
2181 for(ml = (mlist *)oldTile->this; ml != NULL; ml = ml->next)
2182 ml->this->vtile = newTile;
2183 newTile->this = oldTile->this;
2185 /* ---------------------------------------------------------------------------*/
2187 /*---------------------------------------------------------------
2188 * place_partition (Level 2)
2189 * Put a partition down along an edge of partition[0].
2190 *---------------------------------------------------------------
2192 place_partition(part, order)
2193 int part, order;
2195 int i, anchX, anchY, pivX, pivY;
2196 tilist *tl = NULL;
2197 tile *temp;
2198 mlist *ml;
2199 int x, y, side;
2201 /* list the tiles associated with this partition: */
2202 tl = nonFreespace(rootTiles[part], &tl);
2204 /* Set the content-managing functions for this tilespace: */
2205 insert_contents = insert_boxtile_for_partitions;
2206 manage_contents__hmerge = manage_partition_contents_for_merge;
2207 manage_contents__vmerge = manage_partition_contents_for_merge;
2209 if(partitions[0] == NULL)
2211 /* this is the first partition to be placed */
2212 x_positions[part] = 0;
2213 y_positions[part] = 0;
2215 /* Add these tiles to partition[0]: */
2216 for (; (tl != NULL); tl = tl->next)
2218 temp = insert_tile(rootTiles[0], tl->this->x_pos, tl->this->y_pos,
2219 tl->this->x_len, tl->this->y_len, tl->this->this);
2222 else
2224 /* skip empty partitions */
2225 if (partitions[part] == NULL) return; /* return(NULL); */
2227 /* decide where to add this partition: (set the <xSideCount> & <ySideCount>
2228 globals) */
2229 side = best_side_part(part);
2231 if ((xSideCount == 0) && (ySideCount == 0))
2233 default_place_partition(part, &x, &y);
2234 for (; (tl != NULL); tl = tl->next)
2236 temp = insert_tile(rootTiles[0], x + tl->this->x_pos,
2237 y + tl->this->y_pos,
2238 tl->this->x_len, tl->this->y_len, tl->this->this);
2242 else
2244 det_anchor_points(rootTiles[0], xSideCount, ySideCount,
2245 (int)xgbr, (int)ygbr, &anchX, &anchY);
2246 det_pivot_points(rootTiles[part], xSideCount, ySideCount,
2247 (int)xgr, (int)ygr, part, &pivX, &pivY);
2248 normalize_side_counts(&xSideCount, &ySideCount);
2250 temp = angled_group_tile_insertion
2251 (rootTiles[0], anchX, anchY, /* Anchor point */
2252 xSideCount, ySideCount, /* Slope of axis of motion */
2253 pivX, pivY, /* Pivot point (in new tile)*/
2254 &x, &y, /* new origin for this partition */
2255 tl); /* Tiles to insert */
2258 if (temp == NULL) /* This shouldn't happen */
2260 error("place_partition: No valid insertion found!!","");
2261 exit(1);
2264 x_positions[part] = x;
2265 y_positions[part] = y;
2268 /* The rest we also do the first time */
2270 /* adjust the bounding box(es) */
2272 x_sizes[part] += x_positions[part];
2273 y_sizes[part] += y_positions[part];
2275 x_sizes[0] = MAX(x_sizes[0], x_sizes[part]);
2276 y_sizes[0] = MAX(y_sizes[0], y_sizes[part]);
2278 xfloor = MIN(xfloor, x_positions[part]);
2279 yfloor = MIN(yfloor, y_positions[part]);
2281 /* NOTE: we actually update the modules's position, so we do not
2282 * have to keep adding in an offset for the partition's position
2283 * in all future calculations, (like fixup, and for new gravity calcs)
2284 * If we keep this idea, we do not need the positions array, it will
2285 * just be a temp in this routine.
2288 /* move the partition to partition 0 */
2289 for(ml = partitions[part]; ml != NULL; ml = ml->next)
2291 if (ml->this->placed == PLACED)
2293 partitions[0] = (mlist *)concat_list(ml->this, partitions[0]);
2295 /* update the module's position */
2296 ml->this->x_pos += x_positions[part];
2297 ml->this->y_pos += y_positions[part];
2299 /* and mark it as having been added to partitions[0]*/
2300 ml->this->flag = PLACED;
2301 module_info[ml->this->index].order = order++;
2305 /*---------------------------------------------------------------
2306 * set_flag_value(string, flag_val) (Level 3)
2307 * This is to set the ->flag fields within the given module_string
2308 *---------------------------------------------------------------
2310 int set_flag_value(string, flag_val)
2311 mlist *string;
2312 int flag_val;
2314 mlist *ml;
2315 for(ml = string; ml != NULL; ml = ml->next)
2317 ml->this->flag = flag_val;
2320 /*---------------------------------------------------------------
2321 * set_placed_value(string, flag_val) (Level 3)
2322 * This is to set the ->flag fields within the given module_string
2323 *---------------------------------------------------------------
2325 int set_placed_value(string, flag_val)
2326 mlist *string;
2327 int flag_val;
2329 mlist *ml;
2330 for(ml = string; ml != NULL; ml = ml->next)
2332 ml->this->placed = flag_val;
2336 /*---------------------------------------------------------------
2337 * reset_path_trace(path) (Level 3)
2338 * This is to set up the ->flag fields within the given partition
2339 * such that trace_path() will discover the next string that exists
2340 * within the partition.
2341 *---------------------------------------------------------------
2343 int reset_path_trace(mlist *path)
2345 mlist *ml;
2346 for(ml = path; ml != NULL; ml = ml->next)
2348 if (ml->this->placed == UNPLACED) ml->this->flag = UNSEEN;
2352 /*---------------------------------------------------------------
2353 * any_placed_p(string) (Level 3)
2354 * This returns TRUE if any module within the given string is PLACED
2355 *---------------------------------------------------------------
2357 int any_placed_p(string)
2358 mlist *string;
2360 mlist *ml;
2361 for(ml = string; ml != NULL; ml = ml->next)
2363 if (ml->this->placed == PLACED) return(TRUE);
2365 return(FALSE);
2368 /*---------------------------------------------------------------
2369 * Stuff below here should probably be put in utility or another
2370 * helper file
2371 *---------------------------------------------------------------
2375 /*---------------------------------------------------------------
2376 * best_side_part (Level 3)
2377 * Given partition <part>, determin, based on the signal flow, to
2378 * which side of partition[0] it should be placed.
2379 * The new partition is placed on one of the four sides of the bounding
2380 * box of the placed partitions (partition [0]). ALSO,
2381 * as we need to walk through the net anyway, calculate the centers-
2382 * of-gravity for the two partitions (the xl,xb, xt, xr... values)
2384 * --------------------------------------------------------------
2386 int best_side_part(part)
2387 int part;
2389 int top = 0, bot = 0, lef = 0, rig = 0, side, temp;
2390 int xl=0,yl=0,xll=0,yll=0,xr=0,yr=0,xrr=0,yrr=0;
2391 int xt=0,yt=0,xtt=0,ytt=0,xb=0,yb=0,xbb=0,ybb=0;
2392 int ooTemp, iiTemp, ioTempXX, ioTempX, xlSpot = 0, ioTempYY, oiTempX, oiTempY;
2393 int io=0, xio=0, yio=0, xioio=0, yioio=0;
2394 mlist *ml;
2395 tlist *t, *tt;
2397 /* calculate the inputs/outputs between this partition and partition[0]: */
2398 for(ml = partitions[part]; ml != NULL; ml = ml->next)
2400 for(t = ml->this->terms; t != NULL; t = t->next)
2402 if (t->this->nt == NULL) break;
2403 for(tt = t->this->nt->terms; tt != NULL; tt = tt->next)
2405 /* Count how many terminals with nets into the set of
2406 * placed modules we have, and also their postion.
2408 * Also, get the ones from the placed modules
2409 * to this one.
2411 * For x determinations, use the box locations, as these limits
2412 * determine the insertion of new tiles.
2416 if((tt->this->mod->flag == PLACED) && /* its down
2417 (see place_partition())*/
2418 (t->this->mod != tt->this->mod)) /* don't bother with yourself */
2421 /* Handle inout terminal combinations: */
2422 if ((t->this->type == INOUT) || (tt->this->type == INOUT))
2424 if (t->this->type == IN)
2426 xr += t->this->mod->htile->x_pos;
2427 yr += t->this->y_pos + t->this->mod->y_pos;
2428 yrr += tt->this->mod->vtile->y_pos +
2429 tt->this->mod->vtile->y_len;
2430 yrr += tt->this->x_pos + tt->this->mod->x_pos;
2431 rig += 1;
2433 else if (tt->this->type == OUT)
2435 xr += t->this->mod->htile->x_pos;
2436 yr += t->this->y_pos + t->this->mod->y_pos;
2437 xrr += tt->this->x_pos + tt->this->mod->x_pos;
2438 yrr += tt->this->mod->vtile->y_pos +
2439 tt->this->mod->vtile->y_len;
2440 rig += 1;
2442 else if (t->this->type == OUT)
2444 ioTempYY = tt->this->mod->vtile->y_pos +
2445 tt->this->mod->vtile->y_len;
2446 ioTempX = t->this->mod->htile->x_pos +
2447 t->this->mod->htile->x_len;
2448 ioTempXX = tt->this->x_pos + tt->this->mod->x_pos;
2449 if ((((ioTempXX <= xll) || (xll == 0)) ||
2450 ((ioTempXX <= xll) &&
2451 ((ioTempYY <= yll) || (yll == 0))))&&
2452 ((ioTempX >= xlSpot) || (xlSpot == 0)))
2454 xlSpot = ioTempX;
2455 xl = t->this->mod->htile->x_pos +
2456 t->this->mod->htile->x_len;
2457 yl = t->this->y_pos + t->this->mod->y_pos;
2458 xll = tt->this->x_pos + tt->this->mod->x_pos;
2459 yll = tt->this->mod->vtile->y_pos +
2460 tt->this->mod->vtile->y_len;
2462 lef += 1;
2464 else if (tt->this->type == IN)
2466 ioTempYY = tt->this->y_pos + tt->this->mod->y_pos;
2467 ioTempX = t->this->x_pos + t->this->mod->x_pos;
2468 ioTempXX = tt->this->mod->vtile->x_pos;
2469 if ((((ioTempXX <= xll) || (xll == 0)) ||
2470 ((ioTempXX <= xll) &&
2471 ((ioTempYY <= yll) || (yll == 0))))&&
2472 ((ioTempX >= xlSpot) || (xlSpot == 0)))
2474 xlSpot = ioTempX;
2475 yl = t->this->mod->htile->y_pos +
2476 t->this->mod->htile->y_len;
2477 xl = t->this->x_pos + t->this->mod->x_pos;
2478 xll = tt->this->mod->vtile->x_pos;
2479 yll = tt->this->y_pos + tt->this->mod->y_pos;
2481 lef += 1;
2483 else /* INOUT vs INOUT */
2485 yio = t->this->mod->htile->y_pos +
2486 t->this->mod->htile->y_len;
2487 xio = t->this->x_pos + t->this->mod->x_pos;
2488 xioio = tt->this->x_pos + tt->this->mod->x_pos;
2489 yioio = tt->this->mod->vtile->y_pos +
2490 tt->this->mod->vtile->y_len;
2491 io += 1;
2495 /* Normal terminal interactions: */
2496 /* count in-out connections (from P[0] to <part>) */
2497 if (((t->this->type == OUT) && (tt->this->type == IN)) ||
2498 ((t->this->type == INOUT) && (tt->this->type == INOUT)))
2500 if (useAveraging == TRUE)
2502 /* xl += t->this->x_pos + t->this->mod->x_pos; */
2503 xl += t->this->mod->htile->x_pos +
2504 t->this->mod->htile->x_len;
2505 yl += t->this->y_pos + t->this->mod->y_pos;
2506 /* xll += tt->this->x_pos + tt->this->mod->x_pos; */
2507 xll += tt->this->mod->vtile->x_pos;
2508 yll += tt->this->y_pos + tt->this->mod->y_pos;
2510 else /* choose the lowest, furthest left to line up on */
2512 ioTempYY = tt->this->y_pos + tt->this->mod->y_pos;
2513 ioTempX = t->this->mod->x_pos;
2514 ioTempXX = tt->this->mod->vtile->x_pos;
2515 if ((((ioTempXX <= xll) || (xll == 0)) ||
2516 ((ioTempXX <= xll) &&
2517 ((ioTempYY <= yll) || (yll == 0))))&&
2518 ((ioTempX >= xlSpot) || (xlSpot == 0)))
2520 xlSpot = ioTempX;
2521 xl = t->this->mod->htile->x_pos +
2522 t->this->mod->htile->x_len;
2523 yl = t->this->y_pos + t->this->mod->y_pos;
2524 xll = tt->this->mod->vtile->x_pos;
2525 yll = tt->this->y_pos + tt->this->mod->y_pos;
2528 lef += 1;
2531 /* count out-out connections */
2532 if (((t->this->type == OUT) && (tt->this->type == OUT)) ||
2533 ((t->this->type == OUTIN) && (tt->this->type == INOUT)))
2535 temp = tt->this->x_pos + tt->this->mod->x_pos;
2536 if (temp > xbb)
2538 xb = t->this->mod->htile->x_pos +
2539 t->this->mod->htile->x_len;
2540 yb = t->this->y_pos + t->this->mod->y_pos;
2541 /* xbb = tt->this->x_pos + tt->this->mod->x_pos; */
2542 xbb += tt->this->mod->vtile->x_pos +
2543 tt->this->mod->vtile->x_len;
2544 ybb = tt->this->y_pos + tt->this->mod->y_pos;
2546 bot += 1;
2549 /* count out-in connections */
2550 if (((t->this->type == IN) && (tt->this->type == OUT)) ||
2551 ((t->this->type == OUTIN) && (tt->this->type == OUTIN)))
2553 if (1)
2555 xr += t->this->mod->htile->x_pos;
2556 yr += t->this->y_pos + t->this->mod->y_pos;
2557 xrr += tt->this->mod->vtile->x_pos +
2558 tt->this->mod->vtile->x_len;
2559 yrr += tt->this->y_pos + tt->this->mod->y_pos;
2561 else /* choose the highest to line up on */
2563 oiTempY = tt->this->y_pos + tt->this->mod->y_pos;
2564 oiTempX = tt->this->mod->vtile->x_pos +
2565 tt->this->mod->vtile->x_len;
2566 if (oiTempX > xrr)
2568 xr = t->this->mod->htile->x_pos;
2569 yr = t->this->y_pos + t->this->mod->y_pos;
2570 xrr = tt->this->mod->vtile->x_pos +
2571 tt->this->mod->vtile->x_len;
2572 yrr = tt->this->y_pos + tt->this->mod->y_pos;
2574 else if (oiTempY > yrr)
2575 yrr = tt->this->y_pos + tt->this->mod->y_pos;
2577 rig += 1;
2580 /* count in-in connections */
2581 if (((t->this->type == IN) && (tt->this->type == IN)) ||
2582 ((t->this->type == INOUT) && (tt->this->type == OUTIN)))
2584 iiTemp = tt->this->y_pos + tt->this->mod->y_pos;
2585 if (ytt > iiTemp)
2587 xt = t->this->mod->htile->x_pos;
2588 yt = t->this->y_pos + t->this->mod->y_pos;
2589 xtt = tt->this->mod->vtile->x_pos;
2590 ytt = tt->this->y_pos + tt->this->mod->y_pos;
2592 top += 1;
2598 if (top + bot + lef + rig == 0)
2600 /* use inout information */
2601 lef = io;
2602 xl = xio; yl = yio;
2603 xll = xioio; yll = yioio;
2606 /* now figure out which side to put the partition on: */
2607 /* settle any conflicts, otherwise key off of the max value: */
2608 side = choose_side(top, bot, lef, rig);
2609 switch(side) /* ALSO: Handle the tie breakers: */
2611 case UP : { if (top == lef)
2612 { set_gravity_part(part, xl, yl, xll, yll,
2613 (useAveraging == TRUE) ? lef : 1);
2614 side = LEFT;
2615 xSideCount = -1 * lef; /* Overwrite old <xSideCount> */
2616 ySideCount = 0;
2617 break;
2619 else if (top == rig)
2620 { set_gravity_part(part, xr, yr, xrr, yrr,
2621 (1) ? rig : 1);
2622 side = RIGHT;
2623 xSideCount = rig; /* Overwrite old <xSideCount> */
2624 ySideCount = 0;
2625 break;
2627 else if ((lef > 0) && (rig > 0))
2628 { set_gravity_part(part, xl+xr+xt, yl+yr+yt, xll+xrr+xtt,
2629 yll+yrr+ytt, (useAveraging == TRUE) ?
2630 top+lef+rig : 1+rig+1);
2631 break;
2633 else
2634 { set_gravity_part(part, xt, yt, xtt, ytt, 1);
2635 break;
2639 case DOWN : { if (bot == rig)
2641 set_gravity_part(part, xr, yr, xrr, yrr,
2642 (1) ? rig : 1);
2643 side = RIGHT;
2644 xSideCount = rig; /* Overwrite old <xSideCount> */
2645 ySideCount = 0;
2646 break;
2648 else if (bot == lef)
2649 { set_gravity_part(part, xl, yl, xll, yll,
2650 (useAveraging == TRUE) ? lef : 1);
2651 side = LEFT;
2652 xSideCount = -1 * lef;
2653 ySideCount = 0;
2654 break;
2656 else
2657 { set_gravity_part(part, xb, yb, xbb, ybb, 1);
2658 break;
2661 case LEFT : { if (lef == rig)
2662 { set_gravity_part(part, xl+xr, yl+yr, xll+xrr, yll+yrr,
2663 (useAveraging == TRUE) ? lef+rig : rig + 1);
2664 side = UP;
2665 xSideCount = 0; /* Overwrite old <xSideCount> */
2666 ySideCount = 1;
2667 break;
2669 else /* No need to change global side counts */
2670 { set_gravity_part(part, xl, yl, xll, yll,
2671 (useAveraging == TRUE) ? lef : 1);
2672 break;
2676 case RIGHT : { set_gravity_part(part, xr, yr, xrr, yrr,
2677 (1) ? rig : 1);
2678 break;
2681 return (side);
2684 /*---------------------------------------------------------------
2685 * choose_side
2686 * rules for angle selection (placement of boxes & partitions as tiles)
2687 *---------------------------------------------------------------
2689 int choose_side(common_ins, common_outs, in_to, out_of)
2690 int common_ins, common_outs, in_to, out_of;
2693 /* This sets the proper signs for use as the side globals <secSideCount>; */
2694 int max, next_max, mainSide;
2696 if (MAX(in_to, common_ins) >= MAX(out_of, common_outs))
2698 /* inputs (up/left) dominate: */
2699 if (in_to > common_ins)
2701 mainSide = LEFT; max = -1 * in_to;
2702 next_max = (common_outs > common_ins) ? -1 * common_outs : common_ins;
2704 else
2706 mainSide = UP; max = common_ins; next_max = -1 * in_to;
2707 /* next_max = (out_of > in_to) ? out_of : -1 * in_to; */
2710 else
2711 /* outputs (left/bottom) dominate */
2713 if (out_of > common_outs)
2715 mainSide = RIGHT; max = out_of;
2716 next_max = (common_outs > common_ins) ? -1 * common_outs : common_ins;
2718 else
2720 mainSide = DOWN; max = -1 * common_outs; next_max = -1 * in_to;
2721 /* next_max = (out_of > in_to) ? out_of : -1 * in_to; */
2725 /* Set the globals <xSideCount> & ySideCount>, etc: */
2726 xSideCount = ((mainSide == LEFT) || (mainSide == RIGHT)) ? max : next_max;
2727 ySideCount = ((mainSide == UP) || (mainSide == DOWN)) ? max : next_max;
2729 return(mainSide);
2732 /*---------------------------------------------------------------
2733 * set_gravity_part()
2734 *---------------------------------------------------------------
2736 set_gravity_part(p,xb,yb,xbb,ybb,count)
2737 int p,xb,yb,xbb,ybb,count;
2739 if(count > 0)
2741 xgr = xb/(float)count;
2742 ygr = yb/(float)count;
2743 xgbr = xbb/(float)count;
2744 ygbr = ybb/(float)count;
2746 else
2747 { /* stack them, as we don't know what else to do */
2748 xgr = (float)x_sizes[p]/2.0;
2749 ygr = (float)(y_sizes[p] + yfloor);
2750 xgbr = (float)x_sizes[0]/2.0;
2751 ygbr = 0.0;
2752 error("set_gravity_part: partition has no connections to P[0]?");
2756 /*---------------------------------------------------------------
2757 * set_gravity_box()
2758 *---------------------------------------------------------------
2760 set_gravity_box(p,xb,yb,xbb,ybb,count)
2761 int p,xb,yb,xbb,ybb,count;
2762 { /* Set the globals used to place two boxes */
2763 if(count > 0)
2765 xgr = xb/(float)count;
2766 ygr = yb/(float)count;
2767 xgbr = xbb/(float)count;
2768 ygbr = ybb/(float)count;
2770 else
2771 { /* stack these two boxes, as we don't know what else to do */
2773 xgr = (float)(str_length[p]) / 2.0;
2774 ygr = (float)(str_height[p]) / 2.0;
2775 xgbr = (float)(x_sizes[p] - xfloor) / 2.0;
2776 ygbr = (float)(y_sizes[p] - yfloor) / 2.0;
2777 error("set_gravity_box: partition has no connections to P[0]?","");
2780 /*--------------------------------------------------------------------------------
2781 * Count connections (between a box and a partition)
2782 *---------------------------------------------------------------------------------
2784 int count_connections(box, part)
2785 mlist *box;
2786 int part;
2788 tlist *tl, *ttl;
2789 mlist *ml;
2790 int lef = 0, rig = 0, top = 0, bot = 0;
2792 /* calculate the inputs/outputs between this box and the placed modules in
2793 partition[part]: */
2794 for(ml = box; ml != NULL; ml = ml->next)
2796 for(tl = ml->this->terms; tl != NULL; tl = tl->next)
2798 if (tl->this->nt == NULL) break;
2799 for(ttl = tl->this->nt->terms; ttl != NULL; ttl = ttl->next)
2801 /* Count how many terminals with nets into the set of
2802 * placed modules we have, and also their postion.
2804 * And while we are at it, get the ones from the placed modules
2805 * to this one.
2808 if((ttl->this->mod->placed == PLACED) && /* in partitions[part] */
2809 (module_info[tl->this->mod->index].used == part) &&
2810 (module_info[ttl->this->mod->index].used == part) &&
2811 (tl->this->mod != ttl->this->mod) && /* don't bother with yourself */
2812 (find_item(ttl->this->mod->flag, box) == NULL)) /* not in the box */
2814 /* count in-out connections (from P[0] to <part>) */
2815 if (((tl->this->type == OUT) || (tl->this->type == INOUT)) &&
2816 ((ttl->this->type == IN) || (ttl->this->type == INOUT)))
2818 lef += 1;
2821 /* count out-out connections */
2822 if (((tl->this->type == OUT) || (tl->this->type == INOUT)) &&
2823 ((ttl->this->type == OUT) || (ttl->this->type == INOUT)))
2825 bot += 1;
2828 /* count out-in connections */
2829 if (((tl->this->type == IN) || (tl->this->type == INOUT)) &&
2830 ((ttl->this->type == OUT) || (ttl->this->type == INOUT)))
2832 rig += 1;
2835 /* count in-in connections */
2836 if (((tl->this->type == IN) || (tl->this->type == INOUT)) &&
2837 ((ttl->this->type == IN) || (ttl->this->type == INOUT)))
2839 top += 1;
2845 return(top + bot + lef + rig);
2847 /*---------------------------------------------------------------
2848 * best_side_box (Level 3)
2849 * Given partition <part> & some subset of those modules <box>, decide
2850 * which side of the placed partitions in <partitions[]> the given box
2851 * should be placed.
2852 * ALSO: we need to walk through the net anyway, calculate the centers-
2853 * of-gravity for the two partitions (the xl,xb, xt, xr... values)
2855 * --------------------------------------------------------------
2857 int best_side_box(part, box)
2858 int part;
2859 mlist * box;
2862 int top = 0, bot = 0, lef = 0, rig = 0, max, side;
2863 int xl=0,yl=0,xll=0,yll=0,xr=0,yr=0,xrr=0,yrr=0;
2864 int xt=0,yt=0,xtt=0,ytt=0,xb=0,yb=0,xbb=0,ybb=0;
2865 int ooTemp, iiTemp, ioTempX, ioTempY, oiTempX, oiTempY;
2866 mlist *ml;
2867 tlist *t, *tt;
2869 /* calculate the inputs/outputs between this box and the placed modules in
2870 partition[part]: */
2871 for(ml = box; ml != NULL; ml = ml->next)
2873 for(t = ml->this->terms; t != NULL; t = t->next)
2875 if (t->this->nt == NULL) break;
2876 for(tt = t->this->nt->terms; tt != NULL; tt = tt->next)
2878 /* Count how many terminals with nets into the set of
2879 * placed modules we have, and also their postion.
2881 * And while we are at it, get the ones from the placed modules
2882 * to this one.
2885 if((tt->this->mod->placed == PLACED) && /* in partitions[part] */
2886 (module_info[t->this->mod->index].used == part) &&
2887 (module_info[tt->this->mod->index].used == part) &&
2888 (t->this->mod != tt->this->mod) && /* don't bother with yourself */
2889 (find_item(tt->this->mod->flag, box) == NULL)) /* not in the box */
2891 /* count in-out connections (ouput of box to partitions[part]) */
2892 /* old if (((t->this->type == OUT) || (t->this->type == INOUT)) &&
2893 ((tt->this->type == IN) || (tt->this->type == INOUT))) */
2895 if (((t->this->type == OUT) && (tt->this->type == IN)) ||
2896 ((t->this->type == INOUT) && (tt->this->type == INOUT)))
2898 if (useAveraging == TRUE)
2900 xl += t->this->x_pos + t->this->mod->x_pos;
2901 yl += t->this->y_pos + t->this->mod->y_pos;
2902 xll += tt->this->x_pos + tt->this->mod->x_pos;
2903 yll += tt->this->y_pos + tt->this->mod->y_pos;
2905 else /* choose the lowest to line up on */
2907 ioTempY = tt->this->y_pos + tt->this->mod->y_pos;
2908 ioTempX = tt->this->x_pos + tt->this->mod->x_pos;
2909 if ((ioTempX < xll) || (xll == 0))
2911 xl = t->this->x_pos + t->this->mod->x_pos;
2912 yl = t->this->y_pos + t->this->mod->y_pos;
2913 xll = tt->this->x_pos + tt->this->mod->x_pos;
2914 yll = tt->this->y_pos + tt->this->mod->y_pos;
2916 else if (ioTempY < yll)
2917 yll = tt->this->y_pos + tt->this->mod->y_pos;
2919 lef += 1;
2922 /* count out-out connections */
2923 /* old if (((t->this->type == OUT) || (t->this->type == INOUT)) &&
2924 ((tt->this->type == OUT) || (tt->this->type == INOUT))) */
2925 if (((t->this->type == OUT) && (tt->this->type == OUT)) ||
2926 ((t->this->type == OUTIN) && (tt->this->type == INOUT)))
2928 ooTemp = tt->this->x_pos + tt->this->mod->x_pos;
2929 if (ooTemp > xbb)
2931 xb = t->this->x_pos + t->this->mod->x_pos;
2932 yb = t->this->y_pos + t->this->mod->y_pos;
2933 xbb = tt->this->x_pos + tt->this->mod->x_pos;
2934 ybb = tt->this->y_pos + tt->this->mod->y_pos;
2936 bot += 1;
2939 /* count out-in connections */
2940 /* old if (((t->this->type == IN) || (t->this->type == INOUT)) &&
2941 ((tt->this->type == OUT) || (tt->this->type == INOUT))) */
2942 if (((t->this->type == IN) && (tt->this->type == OUT)) ||
2943 ((t->this->type == OUTIN) && (tt->this->type == OUTIN)))
2945 if (useAveraging == TRUE)
2947 xr += t->this->x_pos + t->this->mod->x_pos;
2948 yr += t->this->y_pos + t->this->mod->y_pos;
2949 xrr += tt->this->x_pos + tt->this->mod->x_pos;
2950 yrr += tt->this->y_pos + tt->this->mod->y_pos;
2952 else /* choose the highest to line up on */
2954 oiTempY = tt->this->y_pos + tt->this->mod->y_pos;
2955 oiTempX = tt->this->x_pos + tt->this->mod->x_pos;
2956 if (oiTempX > xrr)
2958 xr = t->this->x_pos + t->this->mod->x_pos;
2959 yr = t->this->y_pos + t->this->mod->y_pos;
2960 xrr = tt->this->x_pos + tt->this->mod->x_pos;
2961 yrr = tt->this->y_pos + tt->this->mod->y_pos;
2963 else if (oiTempY > yrr)
2964 yrr = tt->this->y_pos + tt->this->mod->y_pos;
2966 rig += 1;
2969 /* count in-in connections */
2970 /* old if (((t->this->type == IN) || (t->this->type == INOUT)) &&
2971 ((tt->this->type == IN) || (tt->this->type == INOUT))) */
2972 if (((t->this->type == IN) && (tt->this->type == IN)) ||
2973 ((t->this->type == INOUT) && (tt->this->type == OUTIN)))
2975 /* choose the most forward terminal: */
2976 iiTemp = tt->this->x_pos + tt->this->mod->x_pos;
2977 if (xtt < iiTemp)
2979 xt = t->this->x_pos + t->this->mod->x_pos;
2980 yt = t->this->y_pos + t->this->mod->y_pos;
2981 xtt = tt->this->x_pos + tt->this->mod->x_pos;
2982 ytt = tt->this->y_pos + tt->this->mod->y_pos;
2984 top += 1;
2990 /* now figure out which side to put the partition on: */
2991 /* settle any conflicts, otherwise key off of the max value: */
2992 side = choose_side(top, bot, lef, rig);
2993 switch(side)
2995 case UP : {
2996 if (top == lef)
2997 { set_gravity_box(part, xl, yl, xll, yll,
2998 (useAveraging == TRUE) ? lef : 1);
2999 side = LEFT;
3000 xSideCount = -1 * lef; /* Overwrite old <xSideCount> */
3001 ySideCount = top;
3002 break;
3004 else if (top == rig)
3006 set_gravity_box(part, xr, yr, xrr, yrr,
3007 (useAveraging == TRUE) ? rig : 1);
3008 side = RIGHT;
3009 xSideCount = rig; /* Overwrite old <xSideCount> */
3010 ySideCount = (rig != 1) ? top: 0;
3011 break;
3013 else /* No need to change global side counts */
3014 { set_gravity_box(part, xt, yt, xtt, ytt, 1);
3015 break;
3019 case DOWN : {
3020 if (bot == lef)
3021 { set_gravity_box(part, xl, yl, xll, yll,
3022 (useAveraging == TRUE) ? lef : 1);
3023 side = LEFT;
3024 xSideCount = lef;
3025 ySideCount = -1 * bot;
3026 break;
3028 else if (bot == rig)
3030 set_gravity_box(part, xr, yr, xrr, yrr,
3031 (useAveraging == TRUE) ? rig : 1);
3032 side = RIGHT;
3033 xSideCount = rig; /* Overwrite old <xSideCount> */
3034 ySideCount = (rig != 1) ? -1 * bot : 0;
3035 break;
3037 else /* No need to change global side counts */
3039 set_gravity_box(part, xb, yb, xbb, ybb, 1);
3040 break;
3043 case LEFT : { if (lef == rig)
3044 { if (useAveraging == TRUE)
3045 set_gravity_box(part, xl+xr, yl+yr, xll+xrr, yll+yrr, lef+rig);
3046 else set_gravity_box(part, xl+xr, yl+yr, xll+xrr, yll+yrr, 2);
3047 side = UP;
3048 xSideCount = -1 * lef; /* Overwrite old <xSideCount> */
3049 ySideCount = 0;
3050 break;
3052 else /* No need to change global side counts */
3053 { set_gravity_box(part, xl, yl, xll, yll,
3054 (useAveraging == TRUE) ? lef : 1);
3055 break;
3059 case RIGHT : { /* No need to change global side counts */
3060 set_gravity_box(part, xr, yr, xrr, yrr,
3061 (useAveraging == TRUE) ? rig : 1);
3062 break;
3065 return (side);
3069 /*---------------------------------------------------------------
3070 * fixup_string (Level 2)
3071 * Go back through the string and move everyone up, and over by the amount
3072 * necessary to put the lowest one on the 0 line.
3073 * and the leftmost one on the 0 line. adjust the size too.
3074 *---------------------------------------------------------------
3076 fixup_string(part, xflr, yflr)
3077 int part, xflr, yflr;
3079 mlist *ml;
3081 /* fixup the overal size */
3082 str_length[part] += -(xflr);
3083 str_height[part] += -(yflr);
3084 xfloor = 0;
3085 yfloor = 0;
3087 for(ml = strings[part]; ml != NULL; ml = ml->next)
3089 ml->this->x_pos += -(xflr);
3090 ml->this->y_pos += -(yflr);
3093 /*---------------------------------------------------------------
3094 * move_string (Level 3)
3095 * Go back through the string and move everyone up, and over by the amount
3096 * necessary to put the lowest one on the 0 line.
3097 *---------------------------------------------------------------
3099 move_string(part, xflr, yflr)
3100 int part, xflr, yflr;
3102 mlist *ml;
3104 for(ml = strings[part]; ml != NULL; ml = ml->next)
3106 ml->this->x_pos += xflr;
3107 ml->this->y_pos += yflr;
3110 /*---------------------------------------------------------------
3111 * reset_borders (Level 2)
3112 * Go back through the partition corners, and readjust them.
3113 *---------------------------------------------------------------
3115 reset_borders(xflr, yflr)
3116 int xflr, yflr;
3118 int p;
3119 for (p = 0; p <= partition_count; p++)
3121 /* fixup the overal size */
3122 x_sizes[p] -= xflr;
3123 y_sizes[p] -= yflr;
3124 x_positions[p] -= xflr;
3125 y_positions[p] -= yflr;
3127 x_sizes[0] += xflr;
3128 y_sizes[0] += yflr;
3131 /*---------------------------------------------------------------
3132 * fixup_partition (Level 2)
3133 * Go back through the string and move everyone up, and over by the amount
3134 * necessary to put the lowest one on the 0 line.
3135 * and the leftmost one on the 0 line. adjust the size too.
3136 *---------------------------------------------------------------
3138 fixup_partition(part, xflr, yflr)
3139 int part, xflr, yflr;
3141 mlist *ml = NULL;
3142 tilist *tl = NULL;
3144 /* fixup the overal size */
3145 x_sizes[part] -= xflr;
3146 y_sizes[part] -= yflr;
3148 xfloor = 0;
3149 yfloor = 0;
3151 /* Reset each module individually: */
3152 for(ml = partitions[part]; ml != NULL; ml = ml->next)
3154 if (ml->this->placed == PLACED)
3156 ml->this->x_pos -= xflr;
3157 ml->this->y_pos -= yflr;
3160 /* Reset all the asociated tiles: */
3161 tl = allspace(rootTiles[part], &tl);
3162 tl = translate_origin(tl, -1*xflr, -1*yflr);
3165 /*---------------------------------------------------------------
3166 * line_up_mod (Level 3)
3167 * This calculates the y postion of a module in a string.
3168 * Line up the current module with the previous
3169 * module's output (<prevt>). If the previous module is turned away
3170 * from us, we must allow for bends and jogs.
3171 *---------------------------------------------------------------
3173 int line_up_mod(m, prevt)
3174 module *m;
3175 term *prevt;
3177 int y = 0;
3178 tlist *tl;
3179 term *curr;
3181 if(prevt == NULL)
3183 error("line_up_mod: previous primary terminal NULL","m->name");
3186 /* find the terminal in <m> to line up on: */
3187 for (tl = m->terms; tl != NULL; tl = tl->next)
3189 if (tl->this->nt == prevt->nt)
3191 curr = tl->this;
3192 break;
3196 switch (prevt->side)
3198 case RIGHT:
3199 y = prevt->y_pos + prevt->mod->y_pos - curr->y_pos;
3200 break;
3201 case UP:
3202 y = prevt->y_pos + prevt->mod->y_pos - curr->y_pos +
3203 WHITE_SPACE;
3204 break;
3205 case DOWN:
3206 y = prevt->mod->y_pos - WHITE_SPACE - curr->y_pos;
3207 break;
3208 case LEFT:
3209 if(prevt->mod->y_size > (2 * prevt->y_pos))
3210 { /* go around the bottom */
3211 y = prevt->mod->y_pos - WHITE_SPACE -
3212 curr->y_pos;
3214 else
3215 { /* go around the top */
3216 y = prevt->mod->y_pos + prevt->mod->y_size +
3217 WHITE_SPACE - curr->y_pos;
3219 break;
3220 default:
3222 error("line_up_modules: bad side for previous terminal","");
3223 break;
3226 return(y);
3229 /*---------------------------------------------------------------
3230 * rotate_module (Level 3)
3231 * perform the rotation of the module and terminal positions and sides
3232 *---------------------------------------------------------------
3235 rotate_module(m, rot)
3236 module *m;
3237 int rot;
3239 int xs = m->x_size;
3240 int ys = m->y_size;
3241 tlist *t;
3243 /* Mark the rotation done */
3244 m->rot = rot;
3246 /* update the terminal postions and their sides */
3247 for (t = m->terms; t != NULL; t = t->next)
3249 rot_x_y(rot, xs, ys, t->this);
3250 t->this->side = rot_side(rot, t->this->side);
3253 /* Also update the module's x y sizes (for non-square modules) */
3254 if ((rot == NINETY) || (rot == TWO_SEVENTY))
3256 m->x_size = ys;
3257 m->y_size = xs;
3260 /*---------------------------------------------------------------
3261 * trace_path (Level 4)
3263 * This is a recursive function that performs a depth-first search of
3264 * the modules in the partition that are unplaced, and follow the
3265 * standard output-input (left-right) convention. Modules are marked to
3266 * avoid cycle problems. From the lists generated by traversing the
3267 * child nodes, the longest list seen so far is returned to the parent,
3268 * with the module visited added to the front.
3270 *---------------------------------------------------------------
3272 mlist *trace_path(mod, p, depth, lenWithCC)
3273 module *mod;
3274 int p, depth;
3275 int *lenWithCC;
3277 tlist *t, *tt;
3278 module *nextMod;
3279 mlist *testPath = NULL, *pathSoFar = NULL;
3280 int testLength = 0, lengthSoFar = 0;
3282 depth++;
3284 if(debug_level > 20)
3286 fprintf(stderr,
3287 "Trace_path: Module: %s, Partition: %d, Depth: %d, flag: %d\n",
3288 mod->name, p, depth, mod->flag);
3291 if ((depth <= MAX_DEPTH) && (mod->flag == UNSEEN))
3293 if (mod->placed == UNPLACED) /* only consider unplaced modules */
3295 mod->flag = SEEN; /* don't visit the same node twice */
3297 for (t = mod->terms; t !=NULL; t = t->next)
3299 /* only go from OUT/INOUTs to IN/INOUTs */
3300 if((t->this->type == OUT)||(t->this->type == INOUT))
3302 for(tt = t->this->nt->terms; tt != NULL; tt = tt->next)
3304 nextMod = tt->this->mod;
3306 /* Check each input term on the net */
3307 if((nextMod->index != mod->index) /* not looking at head */
3308 && /* am in partition */
3309 (module_info[nextMod->index].used == p)
3310 && /* Only follow inputs */
3311 ((tt->this->type == IN)||(tt->this->type == INOUT))
3312 && /* not connected to systerm IN */
3313 (strcmp(nextMod->type, "IN"))
3314 && /* not conn'd to systerm INOUT */
3315 (strcmp(nextMod->type, "INOUT"))
3316 && /* not conn'd to a systerm OUT */
3317 (strcmp(nextMod->type, "OUT"))
3319 (nextMod->flag != SEEN))
3321 if (debug_level > 18)/* debug */
3323 fprintf(stderr,
3324 "\t%s, finds: %s through net: %s\n",
3325 mod->name,
3326 nextMod->name,
3327 t->this->nt->name);
3329 /* mark these connections (INOUTs are inelligible) */
3330 if (t->this->type == OUT) mod->primary_out = t->this;
3331 if (tt->this->type == IN) nextMod->primary_in = tt->this;
3332 /* recursive call, adding <nextMod> & all progeny: */
3333 testPath = trace_path(nextMod, p, depth, &testLength);
3335 /* Check to see if this is a cc module */
3336 if((cc_search_level > 0) &&
3337 (cross_coupled_p(mod, nextMod, 1) == TRUE))
3339 pathSoFar = testPath;
3340 lengthSoFar += testLength;
3342 /* if the recursive call found anything new, save the info.*/
3343 else if (testLength > lengthSoFar)
3345 pathSoFar = testPath;
3346 lengthSoFar = testLength;
3348 else /* Clean up markers set while making <testPath> */
3350 reset_path_trace(testPath);
3356 *lenWithCC = lengthSoFar + 1;
3357 return ((mlist *)concat_list(mod, pathSoFar));/* OK-> add this mod to the list */
3361 /* we hit the max length or we hit a node we have already seen */
3362 *lenWithCC = lengthSoFar;
3363 return(NULL);
3366 /*---------------------------------------------------------------
3367 * init_string_arrays (Level 2)
3368 * initialize the boxes, strings, sizes, and positions arrays
3369 * Note: we do one more (number 0) since we do not use partition 0
3370 * (until the very end) and we want to number them 1 to pn.
3371 *---------------------------------------------------------------
3373 int init_string_arrays(p)
3374 int p;
3376 int i;
3378 /* allocate space for the partitions[] matrix, which is built as the partition
3379 assignments are made: */
3380 partitions = (mlist **)calloc((p+3), sizeof(mlist *));
3381 rootTiles = (tile **)calloc((p+3), sizeof(tile *));
3383 strings = (mlist **)calloc((p+1), sizeof(mlist *));
3384 parti_stats = (ctree **)calloc((p+1), sizeof(ctree *));
3385 x_sizes = (int *)calloc((p+1), sizeof(int));
3386 y_sizes = (int *)calloc((p+1), sizeof(int));
3387 x_positions = (int *)calloc((p+1), sizeof(int));
3388 y_positions = (int *)calloc((p+1), sizeof(int));
3389 str_height = (int *)calloc((p+1), sizeof(int));
3390 str_length = (int *)calloc((p+1), sizeof(int));
3392 for(i = 0; i <= p; i++)
3394 rootTiles[i] = create_tile(TILE_SPACE_X_LEN, TILE_SPACE_Y_LEN, NULL,
3395 TILE_SPACE_X_POS, TILE_SPACE_Y_POS);
3396 partitions[i] = NULL;
3397 parti_stats[i] = NULL;
3398 strings[i] = NULL;
3399 x_sizes[i] = 0;
3400 y_sizes[i] = 0;
3401 x_positions[i] = 0;
3402 y_positions[i] = 0;
3403 str_height[i] = 0;
3404 str_length[i] = 0;
3408 /*---------------------------------------------------------------
3409 * is_root (Level 3)
3410 * discover if the module should be used as the root of
3411 * a list of modules (string) which make up a box. The rules in the
3412 * tech-report don't make a lot of sense.
3413 * " a module is allowed to be a root if it has a connection with
3414 * another module in another partion, or if it is connected with
3415 * an in or inout terminal, or if it has just one outgoing net."
3416 * The rule we are using is:
3417 * if it has an in or inout terminal to a module in another partition,
3418 * or if it has an in or inout terminal to a system input net."
3419 *---------------------------------------------------------------
3421 int is_root(m, j)
3422 module *m; /* the module */
3423 int j; /* its index */
3425 int root = 0;
3426 tlist *t, *tt;
3427 int out_count = 0;
3429 #if 0
3430 /* I do not understand this rule:
3431 "if the module has any connections
3432 outside this partition then it is a root"
3434 module_info[j].in = 0;
3435 module_info[j].out = 0;
3436 count_inout(j, module_info[j].used);
3437 if (module_info[j].out)
3439 root = 1;
3440 return(root);
3442 #endif
3444 /* Check to see if it is a system input terminal module */
3445 if ((!strcmp(m->type, "IN")) || (!strcmp(m->type, "INOUT")))
3447 root = 1;
3448 return (root);
3452 /* check all the terminals for this module */
3453 for (t = m->terms; t != NULL; t = t->next)
3455 /* check to see if its an input */
3456 if ((t->this->type == IN)||(t->this->type == INOUT))
3458 /* check to see if its a system input */
3459 if ((t->this->nt->type == IN) || (t->this->nt->type == INOUT))
3461 root = 1;
3462 return(root);
3464 /* see if it connects to a module in another partition */
3465 for(tt = t->this->nt->terms; tt != NULL; tt = tt->next)
3467 if (module_info[tt->this->mod->index].used != module_info[j].used)
3469 root=1;
3470 return(root);
3474 #if 0
3475 else if (t->this->type = OUT)
3477 out_count++;
3479 #endif
3483 #if 0
3484 /* I do not understand this rule either: "just one output" */
3485 if(out_count == 1)
3487 root = 1;
3488 return(root);
3490 #endif
3492 /* default, its not a root */
3493 return(root);
3497 /*---------------------------------------------------------------
3498 * build_connections_amongst_partitions (Level 2)
3499 * run through all the nets and see which modules are connected to
3500 * which others, and by how many nets. This structure is key to
3501 * the partitioning functions. We are hopfully trading space for speed.
3502 * ie, once this monster is built it can be used quickly.
3503 * time = |N| * |B|^2
3504 * NOTE: it might be faster to run from each module, down its
3505 * termlist, and then down their netlists.
3506 * time = |M| * |F| * |B|.
3507 * M = number of modules
3508 * N = number of nets
3509 * B = average branching factor per net
3510 * F = average fanout + fanin per module
3511 *---------------------------------------------------------------
3513 build_connections_amongst_partitions(p, how)
3514 int p,how;
3517 nlist *nl;
3518 tlist *t, *tt;
3519 module *m1, *m2;
3520 int i, j, p1, p2;
3522 /* Zero the relavent portion of the connection matrix (incl. systerm cols/rows) */
3523 for (i = 0; i <= p + 2; i++)
3525 for (j = 0; j <= p + 2; j++)
3527 connected[i][j] = 0;
3530 for (nl = nets; nl != NULL; nl = nl->next)
3532 for (t = nl->this->terms; t != NULL; t = t->next)
3534 m1 = t->this->mod;
3535 if (((m1->placed != UNPLACED) || /* consider placed modules */
3536 (module_info[m1->index].used == p+1) || /* and system terminals */
3537 (module_info[m1->index].used == p+2)) &&
3538 ((how == UNSIGNED)||
3539 ((how == FORWARD) && (t->this->type == OUT) ||
3540 (t->this->type == INOUT)) ||
3541 ((how == REVERSE) && (t->this->type == IN) ||
3542 (t->this->type == INOUT))))
3543 for(tt = nl->this->terms; tt != NULL; tt = tt->next)
3545 m2 = tt->this->mod;
3546 if (((m2->placed != UNPLACED) || /* consider placed modules */
3547 (module_info[m2->index].used == p+1) ||/* and system terminals */
3548 (module_info[m2->index].used == p+2)) &&
3549 ((how == UNSIGNED)||
3550 ((how == REVERSE) && (tt->this->type == OUT) ||
3551 (tt->this->type == INOUT)) ||
3552 ((how == FORWARD) && (tt->this->type == IN) ||
3553 (tt->this->type == INOUT))))
3555 p1 = module_info[m1->index].used;
3556 p2 = module_info[m2->index].used;
3557 if (p1 != p2) connected[p1][p2]++;
3563 /* now overlay this portion of the array, so that the clustering math works out: */
3564 overlay_connections(p + 3, how);
3567 /*---------------------------------------------------------------
3568 * build_connections (Level 2)
3569 * This maps the type of connections being used (POS, UNSIGNED, NEG)
3570 * onto the function to call.
3571 *--------------------------------------------------------------
3573 build_connections(how)
3574 int how;
3576 switch(how)
3578 case FORWARD: { forward_build_connections();
3579 break;
3581 case REVERSE: { reverse_build_connections();
3582 break;
3584 case UNSIGNED: { unsigned_build_connections();
3585 break;
3587 default:
3589 error("build_connections: bad call (%d)");
3590 break;
3595 /*---------------------------------------------------------------
3596 * unsigned_build_connections (Level 3)
3597 * run through all the nets and see which modules are connected to
3598 * which others, and by how many nets. This structure is key to
3599 * the partitioning functions. We are hopfully trading space for speed.
3600 * ie, once this monster is built it can be used quickly.
3601 * time = |N| * |B|^2
3602 * NOTE: it might be faster to run from each module, down its
3603 * termlist, and then down their netlists.
3604 * time = |M| * |F| * |B|.
3605 * M = number of modules
3606 * N = number of nets
3607 * B = average branching factor per net
3608 * F = average fanout + fanin per module
3609 *---------------------------------------------------------------
3611 unsigned_build_connections()
3613 nlist *n;
3614 tlist *t, *tt;
3615 int i, j;
3617 for (i = 0; i < MAX_MOD; i++)
3619 for (j = 0; j < MAX_MOD; j++)
3621 connected[i][j] = 0;
3624 for (n = nets; n != NULL; n = n->next)
3626 for (t = n->this->terms; t != NULL; t = t->next)
3628 for(tt = n->this->terms; tt != NULL; tt = tt->next)
3630 connected[t->this->mod->index][tt->this->mod->index]++;
3635 /*------------------------------------------------------------------------
3636 * Overlay_connections (Level 3)
3637 * This resets the diagonal entries of the useful columns in connected[][].
3638 * The value inserted is the sum of the column entries.
3639 *------------------------------------------------------------------------
3641 int overlay_connections(cl_count, how)
3642 int cl_count, how;
3644 int i, j, sum=0;
3645 for (i=0; i < cl_count; i++)
3647 sum = 0;
3649 /* Now reset the connection matrix for this set of clusters, summing the column, and
3650 * inserting the value on the diagonal: */
3652 for (j=0; j < cl_count; j++)
3654 if (how == FORWARD) sum += connected[j][i]; /* sum the column */
3655 else sum += connected[i][j]; /* sum the row */
3657 connected[i][i] = sum - connected[i][i];
3661 /*---------------------------------------------------------------
3662 * forward_build_connections (Level 2)
3663 * run through all the nets and see which modules are connected to
3664 * which others, and by how many nets. This beast is built such that the
3665 * row item 'feeds' all of the positive entries in the row. In this way,
3666 * one-level (forward) signal flow is mapped.
3668 * This structure is key to the partitioning functions. We are hopfully
3669 * trading space for speed, as this thing is slow to build, but is manipulated
3670 * fairly easily.
3672 * time = |N| * |B|^2
3673 * NOTE: it might be faster to run from each module, down its
3674 * termlist, and then down their netlists.
3675 * time = |M| * |F| * |B|.
3676 * M = number of modules
3677 * N = number of nets
3678 * B = average branching factor per net
3679 * F = average fanout + fanin per module
3680 *---------------------------------------------------------------
3682 forward_build_connections()
3684 mlist *m;
3686 net *n;
3687 tlist *t, *tt;
3688 int i, j;
3690 for (i = 0; i < MAX_MOD; i++)
3692 for (j = 0; j < MAX_MOD; j++)
3694 connected[i][j] = 0;
3697 for (m = modules; m != NULL; m = m->next)
3699 for (t = m->this->terms; t != NULL; t = t->next)
3701 n = t->this->nt;
3702 if ((t->this->type == OUT) || (t->this->type == INOUT))
3704 for(tt = n->terms; tt != NULL; tt = tt->next)
3706 if ((tt->this->type == IN) || (tt->this->type == INOUT))
3707 connected[t->this->mod->index][tt->this->mod->index]++;
3713 /*---------------------------------------------------------------
3714 * reverse_build_connections (Level 2)
3715 * run through all the nets and see which modules are connected to
3716 * which others, and by how many nets. This beast is built such that the
3717 * row item 'is fed by' all of the positive entries in the row. In this way,
3718 * one-level (reverse) signal flow is mapped.
3720 * This structure is key to the partitioning functions. We are hopfully
3721 * trading space for speed, as this thing is slow to build, but is manipulated
3722 * fairly easily.
3724 * time = |N| * |B|^2
3725 * NOTE: it might be faster to run from each module, down its
3726 * termlist, and then down their netlists.
3727 * time = |M| * |F| * |B|.
3728 * M = number of modules
3729 * N = number of nets
3730 * B = average branching factor per net
3731 * F = average fanout + fanin per module
3732 *---------------------------------------------------------------
3734 reverse_build_connections()
3736 mlist *m;
3738 net *n;
3739 tlist *t, *tt;
3740 int i, j;
3742 for (i = 0; i < MAX_MOD; i++)
3744 for (j = 0; j < MAX_MOD; j++)
3746 connected[i][j] = 0;
3749 for (m = modules; m != NULL; m = m->next)
3751 for (t = m->this->terms; t != NULL; t = t->next)
3753 n = t->this->nt;
3754 if ((t->this->type == IN) || (t->this->type == INOUT))
3756 for(tt = n->terms; tt != NULL; tt = tt->next)
3758 if ((tt->this->type == OUT) || (tt->this->type == INOUT))
3759 connected[t->this->mod->index][tt->this->mod->index]++;
3765 /*---------------------------------------------------------------
3766 * reset_connected_matrix (Level 5)
3767 * overwrite the indicated row and column <i> with the information stored
3768 * in the given integer vectors (<col>, <row>).
3769 *---------------------------------------------------------------
3771 reset_connected_matrix(merge, scratch, cCount, actives, col, row, how)
3772 int merge; /* <merge> is the row/column being replaced. */
3773 int scratch; /* <scratch> is the (org) row/column replacing <merge> */
3774 int cCount; /* Number of rows/columns to mess with */
3775 clist **actives; /* Up-to-date ordered list of active clusters */
3776 int *col, *row; /* These are arrays containing the data to replace with */
3777 int how;
3779 int x,y, sum;
3780 clist *cl = *actives;
3781 for (x = 0; x < cCount-1; x++)
3783 if (x < merge)
3785 connected[merge][x] = row[x];
3786 connected[x][merge] = col[x];
3788 else if (x == merge)
3790 connected[merge][x] = row[scratch];
3791 connected[x][merge] = col[scratch];
3793 else if ((x > merge) && ((x < scratch) || (merge == scratch)))
3795 connected[merge][x] = row[x+1];
3796 connected[x][merge] = col[x+1];
3798 else if (x >= scratch)
3800 connected[merge][x] = row[x+1];
3801 connected[x][merge] = col[x+1];
3803 /* <row> & <col> are one element longer than a row/col in the connection mtrx */
3806 /* Restore everyone's diagonal values: */
3807 for (x = 0; x < cCount-1; x++)
3809 connected[x][x] = 0;
3810 sum = 0;
3811 for (y = 0; y < cCount-1; y++)
3813 if (x != y) /* ignore the current diagonal value */
3815 if (how == FORWARD) sum += connected[y][x]; /* sum the column */
3816 else sum += connected[x][y]; /* sum the row */
3819 connected[x][x] = sum;
3820 cl->this->this->connects = sum; /* Update the information in the cluster
3821 structure as well, otherwise the
3822 partitioning functions won't work right. */
3823 cl = cl->next;
3826 /*---------------------------------------------------------------
3827 * find_max_connections_to_P0 (Level 4)
3828 * Return the col/row number that has the highest number of connections
3829 * to partition 0 (the set of placed partitions)
3830 * NOTE: this ignores column 0 of the connection matrix.
3831 *---------------------------------------------------------------
3833 int find_max_connections_to_P0(range)
3834 int range;
3836 int i, partition_0_connections = 0, max = 0, index = 0;
3838 for (i = 1; i <= range; i++)
3840 if ((connected[i][0] > 0) || (connected[0][i] > 0))
3842 partition_0_connections = MAX(connected[0][i], connected[i][0]);
3844 if ((partition_0_connections > max) ||
3845 ((partition_0_connections == max) &&
3846 (connected[i][i] >= connected[index][index])))
3848 max = partition_0_connections;
3849 index = i;
3853 return(index);
3855 /*---------------------------------------------------------------
3856 * find_max_diagonal (Level 4)
3857 * Retrurn the col/row number that has the highest number of connections
3858 * to partition 0 (the set of placed partitions)
3859 * NOTE: this ignores column 0 of the connection matrix.
3860 *---------------------------------------------------------------
3862 int find_max_diagonal(range)
3863 int range;
3865 int i, max = 0, index = 0;
3867 for (i = 1; i <= range; i++)
3869 if (connected[i][i] > max)
3871 max = connected[i][i];
3872 index = i;
3875 return(index);
3878 /*---------------------------------------------------------------
3879 * collect_info (Level 3)
3880 * count how modules are connected in/out of the
3881 * current partition, or with pn=0 in/out of the free set
3883 *---------------------------------------------------------------
3885 collect_info(pn)
3886 int pn;
3888 int i;
3890 for(i = 0; i < module_count; i++)
3892 if(module_info[i].used == 0)
3894 count_inout(i, pn);
3899 /*---------------------------------------------------------------
3900 * count_inout (Level 4)
3901 * count how modules are connected in/out of this partition, to this one
3902 * NOTE: WE ONLY GIVE A COUNT OF 1 FOR ANY NON-ZERO AMOUNT.
3903 *---------------------------------------------------------------
3905 count_inout(m, pn)
3906 int m, pn;
3908 int j;
3910 for(j = 0; j < module_count; j++)
3912 if (m != j)
3914 if (connected[m][j] > 0)
3916 (module_info[j].used != pn ) ?
3917 (module_info[m].out)++ :
3918 (module_info[m].in)++;
3924 /*---------------------------------------------------------------
3925 * reset_info (Level 3)
3926 * initialize temporary information about the partiions of modules
3927 *---------------------------------------------------------------
3929 reset_info()
3931 int i;
3933 for(i = 0; i < module_count; i++)
3935 module_info[i].in = 0;
3936 module_info[i].out = 0;
3940 /*---------------------------------------------------------------
3941 * init_info (Level 2)
3942 * initialize accumulated information about the partitions of modules
3943 *---------------------------------------------------------------
3945 init_info()
3947 int i;
3949 for(i = 0; i < module_count; i++)
3951 module_info[i].used = 0;
3953 reset_info();
3955 /*-------------------------------------------------------------------------------------*/
3956 void print_module_placement(part, f)
3957 int part; /* The partition to see... */
3958 FILE *f; /* The file to dump it to (Better be open!) */
3960 /* This prints a file that can produce a PostScript form of a tile space containing
3961 modules and empty tiles. */
3963 char labelBuffer[30];
3964 mlist *ml;
3965 int i, index;
3967 /* now start the dump file: */
3968 if (latex != TRUE)
3970 ps_print_standard_header(f);
3971 fprintf(f, "\n(%s: Module Placement for ??) %d %d %d %d init\n",
3972 getenv("USER"), xfloor, yfloor, x_sizes[0], y_sizes[0]);
3974 else
3976 ps_print_standard_header(f);
3977 fprintf(f, "swidth setlinewidth\n/Courier findfont fwidth scalefont setfont\n");
3978 fprintf(f,"%%%%BoundingBox: %d %d %d %d\n",
3979 xfloor - CHANNEL_LENGTH, yfloor - CHANNEL_HEIGHT,
3980 x_sizes[0] + CHANNEL_LENGTH, y_sizes[0] + CHANNEL_HEIGHT);
3983 /* Insert all of the tiles into their own tile space */
3984 for (ml = partitions[part]; ml != NULL; ml = ml->next)
3986 ps_print_mod(f, ml->this);
3989 /* Now print the bounderies that surround the various partitions: */
3990 if ((do_routing == FALSE) && (part == 0))
3992 for (i=1; i <= partition_count; i++)
3994 if (partitions[i] != NULL)
3996 index = partitions[i]->this->index;
3997 ps_print_border(f,x_positions[i],y_positions[i],x_sizes[i],y_sizes[i]);
3998 sprintf(labelBuffer, "[part: #%d, placed:%d]",
3999 module_info[index].used, module_info[index].order);
4000 ps_put_label(f, labelBuffer, (float)(x_positions[i] + 1),
4001 (float)(y_sizes[i] - 2));
4005 else if (partitions[part] != NULL)
4007 index = partitions[part]->this->index;
4008 ps_print_border(f, x_positions[part], y_positions[part],
4009 x_sizes[part], y_sizes[part]);
4010 sprintf(labelBuffer, "[part: #%d, placed:%d]\0",
4011 module_info[index].used, module_info[index].order);
4012 ps_put_label(f, labelBuffer, x_positions[part] + 1, y_sizes[part] - 2);
4015 if (latex != TRUE) fprintf(f, "showpage\n");
4018 /*---------------------------------------------------------------
4019 * END OF FILE
4020 *---------------------------------------------------------------