1 /************************************************************
3 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
4 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
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 ************************************************************/
23 /* ------------------------------------------------------------------------
24 * Placement routines spl 7/89
26 * "(Level #)" refers to calling depth from main()
27 * ------------------------------------------------------------------------
33 /*---------------------------------------------------------------
34 * Forward Declarations
35 *---------------------------------------------------------------
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 */
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
55 static int ySideCount
; /* number of conections for the next highest count in
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 /*---------------------------------------------------------------
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 *---------------------------------------------------------------
95 int p_count
= 0, cont
= FALSE
;
96 FILE *temp
= (debug_level
< -3)?fopen("tree_stats", "a"):NULL
;
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));
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 *---------------------------------------------------------------
139 int p_count
= 0, cont
= FALSE
;
143 partition_count
= interpret_block_assignments();
145 init_string_arrays(partition_count
);
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 /*----------------------------------------------------------------------------------*/
160 /* Return TRUE if the two strings are equal, ignoring case */
163 if (strcasecmp(c1
,c2
) == 0) return(TRUE
);
166 /*---------------------------------------------------------------------------------*/
167 int interpret_block_assignments()
170 int i
, p
, partCount
; /* <partCount> corresponds to the length of <table> */
171 list
*l
, *table
= NULL
;
174 /* Loop through all of the names for the modules, and collect block names */
175 /* for each unique block name, create a separate partition */
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
);
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
);
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 */
207 free_list(table
); /* Cleanup */
212 /*---------------------------------------------------------------------------------*/
213 int install_modules()
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
)
236 int (*fn
)(); /* the function to perform at every node */
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 */
255 if (temp
->left
!=NULL
) /* enque the left child */
257 indexed_list_insert(temp
->left
,ilist_length(queue
),&queue
);
261 if (temp
->right
!=NULL
) /* enque the right child */
263 indexed_list_insert(temp
->right
,ilist_length(queue
),&queue
);
266 /* Now do something with the element: */
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);
278 /*---------------------------------------------------------------
279 * tree_breadth (Level 2)
280 * This measures the maximum breadth of the given ctree
281 *--------------------------------------------------------------
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 */
302 if (temp
->left
!=NULL
) /* enque the left child */
304 indexed_list_insert(temp
->left
,ilist_length(queue
),&queue
);
308 if (temp
->right
!=NULL
) /* enque the right child */
310 indexed_list_insert(temp
->right
,ilist_length(queue
),&queue
);
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);
324 /*---------------------------------------------------------------
325 * tree_depth (Level 2)
326 * This measures the maximum depth of the given ctree
327 *--------------------------------------------------------------
334 if (t
== NULL
) return d
;
337 if (t
->right
!= NULL
)
339 r
= tree_depth(t
->right
, ++r
);
343 l
= tree_depth(t
->left
, ++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
)
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;
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
);
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
)
389 { /* recall that this will be called on partial trees */
390 int c
= limb
->this->connects
;
391 int s
= limb
->this->size
;
394 ratio
= (s
> 0) ? (float)c
/(float)s
: 0.0;
396 if ((s
== 1) || (ratio
>= partition_ratio
)) return(TRUE
);
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
)
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
)))
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
)
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
);
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
)
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
)
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
]);
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 *---------------------------------------------------------------
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
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 ");
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
);
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
);
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.");
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
)
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
;
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
;
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: */
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
;
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
),
714 if (parent
->right
!= NULL
) /* finish clipping the left branch */
716 *tree
= parent
->right
;
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
);
725 else if ((r
== TRUE
) && /* clip the right branch */
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
),
737 if (parent
->left
!= NULL
) /* finish clipping the right branch */
739 *tree
= parent
->left
;
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
);
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
)
763 clist
**t
; /* Indexed list of active clusters */
764 int (*acceptance_fn
)();
768 ctree
*r
= (ctree
*)remove_indexed_element(c2
, t
);
769 clist
*merge
= (clist
*)find_indexed_element(c1
, *t
);
773 error("merge_clusters: Passed bad element c1","");
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
);
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
795 *----------------------------------------------------------------
797 int find_next_cluster(c_count
)
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))
812 (float)(connected
[i
][i
] + connected
[j
][j
] - connected
[i
][j
]
814 (float)(connected
[i
][i
] + connected
[j
][j
]);
817 i
= j
= flag
= c_count
; /* exit the loops */
821 /* check to see that smallest was set to something: */
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))
836 (float)(connected
[i
][i
] + connected
[j
][j
] - connected
[i
][j
]
838 (float)(connected
[i
][i
] + connected
[j
][j
]);
840 if ((smallest
>= cvalue
) && (connected
[i
][j
] > 0))
842 smallest
= cvalue
; /* exit with clus1, clus2 set */
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
)
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 */
895 return(TRUE
); /* return both <r1> & <r2> for non-trivial <l> */
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
)
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
))
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
;
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
;
954 for (ml
= path1
; ml
!= NULL
; ml
= ml
->next
)
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
)
979 /*---------------------------------------------------------------
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
1002 *---------------------------------------------------------------
1004 mlist
*longest_path(m
, p
, len
, 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
);
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
;
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"))))
1051 if(debug_level
> 10) /* debug */
1054 "\nNew String: Partition: %d, Root: %s\n",
1056 for(x
= path
; x
!= NULL
; x
= x
->next
)
1058 fprintf(stderr
, "Module: %s\n", x
->this->name
);
1062 else *cmplxLen
= len
;
1066 /*---------------------------------------------------------------
1067 * longest_path_in_part
1068 *---------------------------------------------------------------
1070 mlist
*longest_path_in_part(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
);
1087 connCount
= count_connections(bestPath
, p
);
1089 else if ((len
== bestLen
) &&
1090 (count_connections(path
, p
) > connCount
))
1094 connCount
= count_connections(bestPath
, p
);
1096 else if ((len
== bestLen
) &&
1097 (better_inheritence(path
, bestPath
, p
) == TRUE
))
1101 connCount
= count_connections(bestPath
, p
);
1105 strings
[p
] = bestPath
;
1111 /* ---------------------------------------------------------------------------*/
1112 void insert_boxtile(t
, w
)
1117 /* Mark where the new tile went: */
1118 for(ml
= w
; ml
!= NULL
; ml
= ml
->next
) ml
->this->htile
= t
;
1121 /* ---------------------------------------------------------------------------*/
1122 void manage_string_contents_for_merge(newTile
, oldTile
)
1123 tile
*newTile
, *oldTile
;
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
;
1142 xfloor
= 0; /* initialize the offsets for the placement routines */
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
)
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
;
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
],
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 *---------------------------------------------------------------
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
)
1217 if (strings
[part
] == NULL
) return(0);
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",
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 */
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
)
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
))
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
)
1304 mlist
*ml
, *t
, *given_string
, *top_string
= NULL
;
1305 module
*m
, *cc_m
, *last_m
, *top_cc_mod
= NULL
, *bot_cc_mod
= NULL
;
1307 int tsLength
, lev
, margin
, rot
= 0, cc_flag
= FALSE
, curHeight
;
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)
1332 top_cc_mod
= last_m
;
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>
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",
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
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
));
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 */
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) */
1433 create_rng_varStruct(create_srange(m
->y_pos
- YFUZZ
,
1434 m
->y_pos
+ YFUZZ
, Y
));
1437 /* mark the module as 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
);
1464 /*---------------------------------------------------------------
1465 * box_placement (Level 1)
1466 * should follow module_placement()
1467 *---------------------------------------------------------------
1470 void box_placement()
1472 int i
, len
, start_x
, start_y
;
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
1481 /* remove old connection counts */
1484 /* initialize lower left corner offset */
1488 for(i
= 1; i
<= partition_count
;i
++)
1490 mod
= select_next_box(i
); /* NOT IN USE yields a mod not already placed */
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", "");
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
1511 box
= strings
[i
]; /* Pick up anything added in "place_string" */
1513 mod
= select_next_box(i
);
1517 /*---------------------------------------------------------------
1518 * old_select_next_box (Level 2)
1519 *---------------------------------------------------------------
1521 module
*old_select_next_box(part
)
1524 /* Select the "most connected" unplaced module within the partition */
1526 module
*mod
, *best
= NULL
;
1530 for(ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
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
;
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
)
1557 /* Select the module in the partition that is best connected to the
1558 already-placed modules within the partition. */
1560 module
*mod
, *best
= NULL
;
1561 int count
, bestCount
= 0;
1563 for(ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
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")))
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
)
1584 if (best
== NULL
) return(old_select_next_box(part
));
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
)
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
);
1609 *x
= xfloor
- str_length
[part
];
1610 *y
= (int)(ygbr
- ygr
);
1615 *x
= (int)(xgbr
- xgr
) - xfloor
;
1622 *y
= (int)(ygbr
- ygr
);
1627 *x
= (int)(xgbr
- xgr
) - xfloor
;
1628 *y
= yfloor
- str_height
[part
];
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
)
1645 int xCount
, yCount
, gravX
, gravY
;
1648 /* set the anchor point */
1649 tile
*tt
, *t
= locate(root
, gravX
, gravY
);
1653 /* Just use the gravity points, as calculated. */
1657 else if ((abs(yCount
) > abs(xCount
)) || (xCount
== 0))
1659 /* Just use the gravity points, as calculated. */
1665 /* find the appropriate edge of the tile space: */
1666 if (xCount
> 0) /* right movement, so the anchor goes on the right edge */
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
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. */
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
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
)
1693 if (m1
->x_pos
<= m2
->x_pos
) return(TRUE
);
1696 /*-------------------------------------------------------------------------*/
1697 int vertically(m1
, m2
)
1700 if (m1
->y_pos
<= m2
->y_pos
) return(TRUE
);
1703 /*-------------------------------------------------------------------------*/
1704 det_pivot_points(root
, xCount
, yCount
, gravX
, gravY
, p
, pivX
, pivY
)
1706 int xCount
, yCount
, gravX
, gravY
;
1707 int p
; /* partition number */
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
;
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
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
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
;
1756 /* set the pivot point */
1758 if ((abs(yCount
) > abs(xCount
)) || (xCount
== 0))
1760 /* Just use the gravity points, as calculated. */
1766 /* find the appropriate edge of the tile space: */
1767 if (xCount
< 0) /* left movement, so the pivot goes on the right edge */
1772 else /* right movement, so the pivot goes on the left edge. */
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
)
1803 int side
, loc
, anchX
, anchY
, pivX
, pivY
;
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
);
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 */
1835 if (boxTile
== NULL
) /* This shouldn't happen */
1837 error("place_box: No valid insertion found!!","");
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()
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
);
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()
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",
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));
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
);
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
)
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
)
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
))
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;
2014 case OUTPUT_SYM
: *xPos
= m
->x_pos
;
2016 *xLen
= m
->x_size
= rightSpacing
;
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
;
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
)
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!! */
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 *---------------------------------------------------------------
2077 int p
= partition_count
, old_part
; /* number of partitions */
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
)
2115 /* Unangled, straight-up adjacent placement. All this does is to calculate where
2116 the partition's new origin should be placed at. */
2119 if(partitions
[0] == NULL
)
2121 /* this is the first partition to be placed */
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
);
2136 *x
= xfloor
- (x_sizes
[part
] + CHANNEL_LENGTH
+
2137 WHITE_SPACE
* count_terms_part(part
, RIGHT
));
2138 *y
= (int)(ygbr
- ygr
);
2143 *x
= (int)(xgbr
- xgr
);
2144 *y
= y_sizes
[0] + CHANNEL_HEIGHT
+
2145 WHITE_SPACE
* count_terms_part(part
, DOWN
);
2150 *x
= x_sizes
[0] + CHANNEL_LENGTH
+
2151 WHITE_SPACE
* count_terms_part(part
, LEFT
);
2152 *y
= (int)(ygbr
- ygr
);
2157 *x
= (int)(xgbr
- xgr
);
2158 *y
= yfloor
- (y_sizes
[part
] + CHANNEL_HEIGHT
+
2159 WHITE_SPACE
* count_terms_part(part
, UP
));
2165 /* ---------------------------------------------------------------------------*/
2166 void insert_boxtile_for_partitions(t
, w
)
2171 /* Mark where the new tile went: */
2172 for(ml
= w
; ml
!= NULL
; ml
= ml
->next
) ml
->this->vtile
= t
;
2175 /* ---------------------------------------------------------------------------*/
2176 void manage_partition_contents_for_merge(newTile
, oldTile
)
2177 tile
*newTile
, *oldTile
;
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
)
2195 int i
, anchX
, anchY
, pivX
, pivY
;
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);
2224 /* skip empty partitions */
2225 if (partitions
[part
] == NULL
) return; /* return(NULL); */
2227 /* decide where to add this partition: (set the <xSideCount> & <ySideCount>
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);
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!!","");
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
)
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
)
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
)
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
)
2361 for(ml
= string
; ml
!= NULL
; ml
= ml
->next
)
2363 if (ml
->this->placed
== PLACED
) return(TRUE
);
2368 /*---------------------------------------------------------------
2369 * Stuff below here should probably be put in utility or another
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
)
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;
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
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
;
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
;
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)))
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
;
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)))
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
;
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
;
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)))
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
;
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
;
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
;
2549 /* count out-in connections */
2550 if (((t
->this->type
== IN
) && (tt
->this->type
== OUT
)) ||
2551 ((t
->this->type
== OUTIN
) && (tt
->this->type
== OUTIN
)))
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
;
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
;
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
;
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
;
2598 if (top
+ bot
+ lef
+ rig
== 0)
2600 /* use inout information */
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);
2615 xSideCount
= -1 * lef
; /* Overwrite old <xSideCount> */
2619 else if (top
== rig
)
2620 { set_gravity_part(part
, xr
, yr
, xrr
, yrr
,
2623 xSideCount
= rig
; /* Overwrite old <xSideCount> */
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);
2634 { set_gravity_part(part
, xt
, yt
, xtt
, ytt
, 1);
2639 case DOWN
: { if (bot
== rig
)
2641 set_gravity_part(part
, xr
, yr
, xrr
, yrr
,
2644 xSideCount
= rig
; /* Overwrite old <xSideCount> */
2648 else if (bot
== lef
)
2649 { set_gravity_part(part
, xl
, yl
, xll
, yll
,
2650 (useAveraging
== TRUE
) ? lef
: 1);
2652 xSideCount
= -1 * lef
;
2657 { set_gravity_part(part
, xb
, yb
, xbb
, ybb
, 1);
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);
2665 xSideCount
= 0; /* Overwrite old <xSideCount> */
2669 else /* No need to change global side counts */
2670 { set_gravity_part(part
, xl
, yl
, xll
, yll
,
2671 (useAveraging
== TRUE
) ? lef
: 1);
2676 case RIGHT
: { set_gravity_part(part
, xr
, yr
, xrr
, yrr
,
2684 /*---------------------------------------------------------------
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
;
2706 mainSide
= UP
; max
= common_ins
; next_max
= -1 * in_to
;
2707 /* next_max = (out_of > in_to) ? out_of : -1 * in_to; */
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
;
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
;
2732 /*---------------------------------------------------------------
2733 * set_gravity_part()
2734 *---------------------------------------------------------------
2736 set_gravity_part(p
,xb
,yb
,xbb
,ybb
,count
)
2737 int p
,xb
,yb
,xbb
,ybb
,count
;
2741 xgr
= xb
/(float)count
;
2742 ygr
= yb
/(float)count
;
2743 xgbr
= xbb
/(float)count
;
2744 ygbr
= ybb
/(float)count
;
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;
2752 error("set_gravity_part: partition has no connections to P[0]?");
2756 /*---------------------------------------------------------------
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 */
2765 xgr
= xb
/(float)count
;
2766 ygr
= yb
/(float)count
;
2767 xgbr
= xbb
/(float)count
;
2768 ygbr
= ybb
/(float)count
;
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
)
2790 int lef
= 0, rig
= 0, top
= 0, bot
= 0;
2792 /* calculate the inputs/outputs between this box and the placed modules in
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
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
)))
2821 /* count out-out connections */
2822 if (((tl
->this->type
== OUT
) || (tl
->this->type
== INOUT
)) &&
2823 ((ttl
->this->type
== OUT
) || (ttl
->this->type
== INOUT
)))
2828 /* count out-in connections */
2829 if (((tl
->this->type
== IN
) || (tl
->this->type
== INOUT
)) &&
2830 ((ttl
->this->type
== OUT
) || (ttl
->this->type
== INOUT
)))
2835 /* count in-in connections */
2836 if (((tl
->this->type
== IN
) || (tl
->this->type
== INOUT
)) &&
2837 ((ttl
->this->type
== IN
) || (ttl
->this->type
== INOUT
)))
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
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
)
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
;
2869 /* calculate the inputs/outputs between this box and the placed modules in
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
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
);
2997 { set_gravity_box(part
, xl
, yl
, xll
, yll
,
2998 (useAveraging
== TRUE
) ? lef
: 1);
3000 xSideCount
= -1 * lef
; /* Overwrite old <xSideCount> */
3004 else if (top
== rig
)
3006 set_gravity_box(part
, xr
, yr
, xrr
, yrr
,
3007 (useAveraging
== TRUE
) ? rig
: 1);
3009 xSideCount
= rig
; /* Overwrite old <xSideCount> */
3010 ySideCount
= (rig
!= 1) ? top
: 0;
3013 else /* No need to change global side counts */
3014 { set_gravity_box(part
, xt
, yt
, xtt
, ytt
, 1);
3021 { set_gravity_box(part
, xl
, yl
, xll
, yll
,
3022 (useAveraging
== TRUE
) ? lef
: 1);
3025 ySideCount
= -1 * bot
;
3028 else if (bot
== rig
)
3030 set_gravity_box(part
, xr
, yr
, xrr
, yrr
,
3031 (useAveraging
== TRUE
) ? rig
: 1);
3033 xSideCount
= rig
; /* Overwrite old <xSideCount> */
3034 ySideCount
= (rig
!= 1) ? -1 * bot
: 0;
3037 else /* No need to change global side counts */
3039 set_gravity_box(part
, xb
, yb
, xbb
, ybb
, 1);
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);
3048 xSideCount
= -1 * lef
; /* Overwrite old <xSideCount> */
3052 else /* No need to change global side counts */
3053 { set_gravity_box(part
, xl
, yl
, xll
, yll
,
3054 (useAveraging
== TRUE
) ? lef
: 1);
3059 case RIGHT
: { /* No need to change global side counts */
3060 set_gravity_box(part
, xr
, yr
, xrr
, yrr
,
3061 (useAveraging
== TRUE
) ? rig
: 1);
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
;
3081 /* fixup the overal size */
3082 str_length
[part
] += -(xflr
);
3083 str_height
[part
] += -(yflr
);
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
;
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
)
3119 for (p
= 0; p
<= partition_count
; p
++)
3121 /* fixup the overal size */
3124 x_positions
[p
] -= xflr
;
3125 y_positions
[p
] -= 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
;
3144 /* fixup the overal size */
3145 x_sizes
[part
] -= xflr
;
3146 y_sizes
[part
] -= yflr
;
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
)
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
)
3196 switch (prevt
->side
)
3199 y
= prevt
->y_pos
+ prevt
->mod
->y_pos
- curr
->y_pos
;
3202 y
= prevt
->y_pos
+ prevt
->mod
->y_pos
- curr
->y_pos
+
3206 y
= prevt
->mod
->y_pos
- WHITE_SPACE
- curr
->y_pos
;
3209 if(prevt
->mod
->y_size
> (2 * prevt
->y_pos
))
3210 { /* go around the bottom */
3211 y
= prevt
->mod
->y_pos
- WHITE_SPACE
-
3215 { /* go around the top */
3216 y
= prevt
->mod
->y_pos
+ prevt
->mod
->y_size
+
3217 WHITE_SPACE
- curr
->y_pos
;
3222 error("line_up_modules: bad side for previous terminal","");
3229 /*---------------------------------------------------------------
3230 * rotate_module (Level 3)
3231 * perform the rotation of the module and terminal positions and sides
3232 *---------------------------------------------------------------
3235 rotate_module(m
, rot
)
3243 /* Mark the rotation done */
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
))
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
)
3279 mlist
*testPath
= NULL
, *pathSoFar
= NULL
;
3280 int testLength
= 0, lengthSoFar
= 0;
3284 if(debug_level
> 20)
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 */
3324 "\t%s, finds: %s through net: %s\n",
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
;
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
)
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
;
3408 /*---------------------------------------------------------------
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 *---------------------------------------------------------------
3422 module
*m
; /* the module */
3423 int j
; /* its index */
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
)
3444 /* Check to see if it is a system input terminal module */
3445 if ((!strcmp(m
->type
, "IN")) || (!strcmp(m
->type
, "INOUT")))
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
))
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
)
3475 else if (t
->this->type
= OUT
)
3484 /* I do not understand this rule either: "just one output" */
3492 /* default, its not a 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
)
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
)
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
)
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
)
3578 case FORWARD
: { forward_build_connections();
3581 case REVERSE
: { reverse_build_connections();
3584 case UNSIGNED
: { unsigned_build_connections();
3589 error("build_connections: bad call (%d)");
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()
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
)
3645 for (i
=0; i
< cl_count
; i
++)
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
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()
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
)
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
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()
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
)
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 */
3780 clist
*cl
= *actives
;
3781 for (x
= 0; x
< cCount
-1; x
++)
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;
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. */
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
)
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
;
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
)
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
];
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 *---------------------------------------------------------------
3890 for(i
= 0; i
< module_count
; i
++)
3892 if(module_info
[i
].used
== 0)
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 *---------------------------------------------------------------
3910 for(j
= 0; j
< module_count
; 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 *---------------------------------------------------------------
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 *---------------------------------------------------------------
3949 for(i
= 0; i
< module_count
; i
++)
3951 module_info
[i
].used
= 0;
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];
3967 /* now start the dump file: */
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]);
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 /*---------------------------------------------------------------
4020 *---------------------------------------------------------------