abc-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
place_partition.c
Go to the documentation of this file.
1 /*===================================================================*/
2 //
3 // place_partition.c
4 //
5 // Aaron P. Hurst, 2003-2007
6 // ahurst@eecs.berkeley.edu
7 //
8 /*===================================================================*/
9 
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <limits.h>
15 #include <assert.h>
16 //#include <sys/stat.h>
17 //#include <unistd.h>
18 
19 #include "place_base.h"
20 #include "place_gordian.h"
21 
22 #if !defined(NO_HMETIS)
23 #include "libhmetis.h"
24 
26 
27 #endif
28 
29 // --------------------------------------------------------------------
30 // Global variables
31 //
32 // --------------------------------------------------------------------
33 
36  **allNetsL2 = NULL,
37  **allNetsB2 = NULL,
38  **allNetsT2 = NULL;
39 
40 
41 // --------------------------------------------------------------------
42 // Function prototypes and local data structures
43 //
44 // --------------------------------------------------------------------
45 
46 typedef struct FM_cell {
47  int loc;
48  int gain;
50  struct FM_cell *next, *prev;
51  bool locked;
52 } FM_cell;
53 
54 void FM_updateGains(ConcreteNet *net, int partition, int inc,
55  FM_cell target [], FM_cell *bin [],
56  int count_1 [], int count_2 []);
57 
58 
59 // --------------------------------------------------------------------
60 // initPartitioning()
61 //
62 /// \brief Initializes data structures necessary for partitioning.
63 //
64 /// Creates a valid g_place_rootPartition.
65 ///
66 // --------------------------------------------------------------------
68  int i;
69  float area;
70 
71  // create root partition
73  if (g_place_rootPartition) free(g_place_rootPartition);
74  g_place_rootPartition = malloc(sizeof(Partition));
75  g_place_rootPartition->m_level = 0;
76  g_place_rootPartition->m_area = 0;
77  g_place_rootPartition->m_bounds = g_place_coreBounds;
78  g_place_rootPartition->m_vertical = false;
79  g_place_rootPartition->m_done = false;
80  g_place_rootPartition->m_leaf = true;
81 
82  // add all of the cells to this partition
83  g_place_rootPartition->m_members = malloc(sizeof(ConcreteCell*)*g_place_numCells);
84  g_place_rootPartition->m_numMembers = 0;
85  for (i=0; i<g_place_numCells; i++)
86  if (g_place_concreteCells[i]) {
87  if (!g_place_concreteCells[i]->m_fixed) {
89  g_place_rootPartition->m_members[g_place_rootPartition->m_numMembers++] =
91  g_place_rootPartition->m_area += area;
92  }
93  }
94 }
95 
96 
97 // --------------------------------------------------------------------
98 // presortNets()
99 //
100 /// \brief Sorts nets by corner positions.
101 //
102 /// Allocates allNetsX2 structures.
103 ///
104 // --------------------------------------------------------------------
105 void presortNets() {
107  allNetsR2 = (ConcreteNet**)realloc(allNetsR2, sizeof(ConcreteNet*)*g_place_numNets);
114  qsort(allNetsL2, g_place_numNets, sizeof(ConcreteNet*), netSortByL);
115  qsort(allNetsR2, g_place_numNets, sizeof(ConcreteNet*), netSortByR);
116  qsort(allNetsB2, g_place_numNets, sizeof(ConcreteNet*), netSortByB);
117  qsort(allNetsT2, g_place_numNets, sizeof(ConcreteNet*), netSortByT);
118 }
119 
120 // --------------------------------------------------------------------
121 // refinePartitions()
122 //
123 /// \brief Splits large leaf partitions.
124 //
125 // --------------------------------------------------------------------
127 
128  return refinePartition(g_place_rootPartition);
129 }
130 
131 
132 // --------------------------------------------------------------------
133 // reallocPartitions()
134 //
135 /// \brief Reallocates the partitions based on placement information.
136 //
137 // --------------------------------------------------------------------
139 
140  reallocPartition(g_place_rootPartition);
141 }
142 
143 
144 // --------------------------------------------------------------------
145 // refinePartition()
146 //
147 /// \brief Splits any large leaves within a partition.
148 //
149 // --------------------------------------------------------------------
151  bool degenerate = false;
152  int nonzeroCount = 0;
153  int i;
154 
155  assert(p);
156 
157  // is this partition completed?
158  if (p->m_done) return true;
159 
160  // is this partition a non-leaf node?
161  if (!p->m_leaf) {
162  p->m_done = refinePartition(p->m_sub1);
163  p->m_done &= refinePartition(p->m_sub2);
164  return p->m_done;
165  }
166 
167  // leaf...
168  // create two new subpartitions
170  p->m_sub1 = malloc(sizeof(Partition));
171  p->m_sub1->m_level = p->m_level+1;
172  p->m_sub1->m_leaf = true;
173  p->m_sub1->m_done = false;
174  p->m_sub1->m_area = 0;
175  p->m_sub1->m_vertical = !p->m_vertical;
176  p->m_sub1->m_numMembers = 0;
177  p->m_sub1->m_members = NULL;
178  p->m_sub2 = malloc(sizeof(Partition));
179  p->m_sub2->m_level = p->m_level+1;
180  p->m_sub2->m_leaf = true;
181  p->m_sub2->m_done = false;
182  p->m_sub2->m_area = 0;
183  p->m_sub2->m_vertical = !p->m_vertical;
184  p->m_sub2->m_numMembers = 0;
185  p->m_sub2->m_members = NULL;
186  p->m_leaf = false;
187 
188  // --- INITIAL PARTITION
189 
192  else
194 
195  resizePartition(p);
196 
197  // --- PARTITION IMPROVEMENT
198 
199  if (p->m_level < REPARTITION_LEVEL_DEPTH) {
200  if (REPARTITION_FM)
201  repartitionFM(p);
202  else if (REPARTITION_HMETIS)
204  }
205 
206  resizePartition(p);
207 
208  // fix imbalances due to zero-area cells
209  for(i=0; i<p->m_sub1->m_numMembers; i++)
210  if (p->m_sub1->m_members[i])
211  if (getCellArea(p->m_sub1->m_members[i]) > 0) {
212  nonzeroCount++;
213  }
214 
215  // is this leaf now done?
216  if (nonzeroCount <= LARGEST_FINAL_SIZE)
217  p->m_sub1->m_done = true;
218  if (nonzeroCount == 0)
219  degenerate = true;
220 
221  nonzeroCount = 0;
222  for(i=0; i<p->m_sub2->m_numMembers; i++)
223  if (p->m_sub2->m_members[i])
224  if (getCellArea(p->m_sub2->m_members[i]) > 0) {
225  nonzeroCount++;
226  }
227 
228  // is this leaf now done?
229  if (nonzeroCount <= LARGEST_FINAL_SIZE)
230  p->m_sub2->m_done = true;
231  if (nonzeroCount == 0)
232  degenerate = true;
233 
234  // have we found a degenerate partitioning?
235  if (degenerate) {
236  printf("QPART-35 : WARNING: degenerate partition generated\n");
238  resizePartition(p);
239  p->m_sub1->m_done = true;
240  p->m_sub2->m_done = true;
241  }
242 
243  // is this parent now finished?
244  if (p->m_sub1->m_done && p->m_sub2->m_done) p->m_done = true;
245 
246  return p->m_done;
247 }
248 
249 
250 // --------------------------------------------------------------------
251 // repartitionHMetis()
252 //
253 /// \brief Repartitions the two subpartitions using the hMetis min-cut library.
254 ///
255 /// The number of cut nets between the two partitions will be minimized.
256 //
257 // --------------------------------------------------------------------
259 #if defined(NO_HMETIS)
260  printf("QPAR_02 : \t\tERROR: hMetis not available. Ignoring.\n");
261 #else
262 
263  int n,c,t, i;
264  float area;
265  int *edgeConnections = NULL;
266  int *partitionAssignment = (int *)calloc(g_place_numCells, sizeof(int));
267  int *vertexWeights = (int *)calloc(g_place_numCells, sizeof(int));
268  int *edgeDegree = (int *)malloc(sizeof(int)*(g_place_numNets+1));
269  int numConnections = 0;
270  int numEdges = 0;
271  float initial_cut;
272  int targets = 0;
273  ConcreteCell *cell = NULL;
274  int options[9];
275  int afterCuts = 0;
276 
277  assert(parent);
278  assert(parent->m_sub1);
279  assert(parent->m_sub2);
280 
281  printf("QPAR-02 : \t\trepartitioning with hMetis\n");
282 
283  // count edges
284  edgeDegree[0] = 0;
285  for(n=0; n<g_place_numNets; n++) if (g_place_concreteNets[n])
286  if (g_place_concreteNets[n]->m_numTerms > 1) {
287  numConnections += g_place_concreteNets[n]->m_numTerms;
288  edgeDegree[++numEdges] = numConnections;
289  }
290 
291  if (parent->m_vertical) {
292  // vertical
293  initial_cut = parent->m_sub2->m_bounds.x;
294 
295  // initialize all cells
296  for(c=0; c<g_place_numCells; c++) if (g_place_concreteCells[c]) {
297  if (g_place_concreteCells[c]->m_x < initial_cut)
298  partitionAssignment[c] = 0;
299  else
300  partitionAssignment[c] = 1;
301  }
302 
303  // initialize cells in partition 1
304  for(t=0; t<parent->m_sub1->m_numMembers; t++) if (parent->m_sub1->m_members[t]) {
305  cell = parent->m_sub1->m_members[t];
306  vertexWeights[cell->m_id] = getCellArea(cell);
307  // pay attention to cells that are close to the cut
308  if (abs(cell->m_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
309  targets++;
310  partitionAssignment[cell->m_id] = -1;
311  }
312  }
313 
314  // initialize cells in partition 2
315  for(t=0; t<parent->m_sub2->m_numMembers; t++) if (parent->m_sub2->m_members[t]) {
316  cell = parent->m_sub2->m_members[t];
317  vertexWeights[cell->m_id] = getCellArea(cell);
318  // pay attention to cells that are close to the cut
319  if (abs(cell->m_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
320  targets++;
321  partitionAssignment[cell->m_id] = -1;
322  }
323  }
324 
325  } else {
326  // horizontal
327  initial_cut = parent->m_sub2->m_bounds.y;
328 
329  // initialize all cells
330  for(c=0; c<g_place_numCells; c++) if (g_place_concreteCells[c]) {
331  if (g_place_concreteCells[c]->m_y < initial_cut)
332  partitionAssignment[c] = 0;
333  else
334  partitionAssignment[c] = 1;
335  }
336 
337  // initialize cells in partition 1
338  for(t=0; t<parent->m_sub1->m_numMembers; t++) if (parent->m_sub1->m_members[t]) {
339  cell = parent->m_sub1->m_members[t];
340  vertexWeights[cell->m_id] = getCellArea(cell);
341  // pay attention to cells that are close to the cut
342  if (abs(cell->m_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
343  targets++;
344  partitionAssignment[cell->m_id] = -1;
345  }
346  }
347 
348  // initialize cells in partition 2
349  for(t=0; t<parent->m_sub2->m_numMembers; t++) if (parent->m_sub2->m_members[t]) {
350  cell = parent->m_sub2->m_members[t];
351  vertexWeights[cell->m_id] = getCellArea(cell);
352  // pay attention to cells that are close to the cut
353  if (abs(cell->m_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
354  targets++;
355  partitionAssignment[cell->m_id] = -1;
356  }
357  }
358  }
359 
360  options[0] = 1; // any non-default values?
361  options[1] = 3; // num bisections
362  options[2] = 1; // grouping scheme
363  options[3] = 1; // refinement scheme
364  options[4] = 1; // cycle refinement scheme
365  options[5] = 0; // reconstruction scheme
366  options[6] = 0; // fixed assignments?
367  options[7] = 12261980; // random seed
368  options[8] = 0; // debugging level
369 
370  edgeConnections = (int *)malloc(sizeof(int)*numConnections);
371 
372  i = 0;
373  for(n=0; n<g_place_numNets; n++) if (g_place_concreteNets[n]) {
374  if (g_place_concreteNets[n]->m_numTerms > 1)
375  for(t=0; t<g_place_concreteNets[n]->m_numTerms; t++)
376  edgeConnections[i++] = g_place_concreteNets[n]->m_terms[t]->m_id;
377  }
378 
379  HMETIS_PartRecursive(g_place_numCells, numEdges, vertexWeights,
380  edgeDegree, edgeConnections, NULL,
381  2, (int)(100*MAX_PARTITION_NONSYMMETRY),
382  options, partitionAssignment, &afterCuts);
383 
384  /*
385  printf("HMET-20 : \t\t\tbalance before %d / %d ... ", parent->m_sub1->m_numMembers,
386  parent->m_sub2->m_numMembers);
387  */
388 
389  // reassign members to subpartitions
390  parent->m_sub1->m_numMembers = 0;
391  parent->m_sub1->m_area = 0;
392  parent->m_sub2->m_numMembers = 0;
393  parent->m_sub2->m_area = 0;
394  parent->m_sub1->m_members = (ConcreteCell**)realloc(parent->m_sub1->m_members,
395  sizeof(ConcreteCell*)*parent->m_numMembers);
396  parent->m_sub2->m_members = (ConcreteCell**)realloc(parent->m_sub2->m_members,
397  sizeof(ConcreteCell*)*parent->m_numMembers);
398 
399  for(t=0; t<parent->m_numMembers; t++) if (parent->m_members[t]) {
400  cell = parent->m_members[t];
401  area = getCellArea(cell);
402  if (partitionAssignment[cell->m_id] == 0) {
403  parent->m_sub1->m_members[parent->m_sub1->m_numMembers++] = cell;
404  parent->m_sub1->m_area += area;
405  }
406  else {
407  parent->m_sub2->m_members[parent->m_sub2->m_numMembers++] = cell;
408  parent->m_sub2->m_area += area;
409  }
410  }
411  /*
412  printf("after %d / %d\n", parent->m_sub1->m_numMembers,
413  parent->m_sub2->m_numMembers);
414  */
415 
416  // cout << "HMET-21 : \t\t\tloc: " << initial_cut << " targetting: " << targets*100/parent->m_members.length() << "%" << endl;
417  // cout << "HMET-22 : \t\t\tstarting cuts= " << beforeCuts << " final cuts= " << afterCuts << endl;
418 
419  free(edgeConnections);
420  free(vertexWeights);
421  free(edgeDegree);
422  free(partitionAssignment);
423 #endif
424 }
425 
426 
427 // --------------------------------------------------------------------
428 // repartitionFM()
429 //
430 /// \brief Fiduccia-Matheyses mincut partitioning algorithm.
431 //
432 /// UNIMPLEMENTED (well, un-C-ified)
433 //
434 // --------------------------------------------------------------------
435 void repartitionFM(Partition *parent) {
436 #if 0
437  assert(!parent->leaf && parent->m_sub1->leaf && parent->m_sub2->leaf);
438 
439  // count of each net's number of cells in each bipartition
440  int count_1[m_design->nets.length()];
441  memset(count_1, 0, sizeof(int)*m_design->nets.length());
442  int count_2[m_design->nets.length()];
443  memset(count_2, 0, sizeof(int)*m_design->nets.length());
444 
445  FM_cell target[m_design->cells.length()];
446  memset(target, 0, sizeof(FM_cell)*m_design->cells.length());
447  FM_cell *bin[FM_MAX_BIN+1];
448  FM_cell *locked = 0;
449  memset(bin, 0, sizeof(FM_cell *)*(FM_MAX_BIN+1));
450 
451  int max_gain = 0;
452  int before_cuts = 0, current_cuts = 0;
453  double initial_cut;
454  int targets = 0;
455  long cell_id;
456  double halfArea = parent->m_area / 2.0;
457  double areaFlexibility = parent->m_area * MAX_PARTITION_NONSYMMETRY;
458  ConcreteNet *net;
459 
460  // INITIALIZATION
461  // select cells to partition
462 
463  if (parent->vertical) {
464  // vertical
465 
466  initial_cut = parent->m_sub2->m_bounds.x;
467 
468  // initialize all cells
469  for(h::list<ConcreteCell *>::iterator it = rootPartition->m_members.begin(); !it; it++) {
470  cell_id = (*it)->getID();
471  if ((*it)->temp_x < initial_cut)
472  target[cell_id].loc = -1;
473  else
474  target[cell_id].loc = -2;
475  target[cell_id].cell = *it;
476  target[cell_id].gain = 0;
477  }
478 
479  // initialize cells in partition 1
480  for(h::list<ConcreteCell *>::iterator it = parent->m_sub1->m_members.begin(); !it; it++) {
481  cell_id = (*it)->getID();
482  // pay attention to cells that are close to the cut
483  if (abs((*it)->temp_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
484  targets++;
485  target[cell_id].loc = 1;
486  }
487  }
488 
489  // initialize cells in partition 2
490  for(h::list<ConcreteCell *>::iterator it = parent->m_sub2->m_members.begin(); !it; it++) {
491  cell_id = (*it)->getID();
492  // pay attention to cells that are close to the cut
493  if (abs((*it)->temp_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
494  targets++;
495  target[cell_id].loc = 2;
496  }
497  }
498 
499  // count the number of cells on each side of the partition for every net
500  for(h::hash_map<ConcreteNet *>::iterator n_it = m_design->nets.begin(); !n_it; n_it++) {
501  for(ConcretePinList::iterator p_it = (net = *n_it)->getPins().begin(); !p_it; p_it++)
502  if (abs(target[(*p_it)->getCell()->getID()].loc) == 1)
503  count_1[net->getID()]++;
504  else if (abs(target[(*p_it)->getCell()->getID()].loc) == 2)
505  count_2[net->getID()]++;
506  else if ((*p_it)->getCell()->temp_x < initial_cut)
507  count_1[net->getID()]++;
508  else
509  count_2[net->getID()]++;
510  if (count_1[net->getID()] > 0 && count_2[net->getID()] > 0) before_cuts++;
511  }
512 
513  } else {
514  // horizontal
515 
516  initial_cut = parent->m_sub2->m_bounds.y;
517 
518  // initialize all cells
519  for(h::list<ConcreteCell *>::iterator it = rootPartition->m_members.begin(); !it; it++) {
520  cell_id = (*it)->getID();
521  if ((*it)->temp_y < initial_cut)
522  target[cell_id].loc = -1;
523  else
524  target[cell_id].loc = -2;
525  target[cell_id].cell = *it;
526  target[cell_id].gain = 0;
527  }
528 
529  // initialize cells in partition 1
530  for(h::list<ConcreteCell *>::iterator it = parent->m_sub1->m_members.begin(); !it; it++) {
531  cell_id = (*it)->getID();
532  // pay attention to cells that are close to the cut
533  if (abs((*it)->temp_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
534  targets++;
535  target[cell_id].loc = 1;
536  }
537  }
538 
539  // initialize cells in partition 2
540  for(h::list<ConcreteCell *>::iterator it = parent->m_sub2->m_members.begin(); !it; it++) {
541  cell_id = (*it)->getID();
542  // pay attention to cells that are close to the cut
543  if (abs((*it)->temp_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
544  targets++;
545  target[cell_id].loc = 2;
546  }
547  }
548 
549  // count the number of cells on each side of the partition for every net
550  for(h::hash_map<ConcreteNet *>::iterator n_it = m_design->nets.begin(); !n_it; n_it++) {
551  for(ConcretePinList::iterator p_it = (net = *n_it)->getPins().begin(); !p_it; p_it++)
552  if (abs(target[(*p_it)->getCell()->getID()].loc) == 1)
553  count_1[net->getID()]++;
554  else if (abs(target[(*p_it)->getCell()->getID()].loc) == 2)
555  count_2[net->getID()]++;
556  else if ((*p_it)->getCell()->temp_y < initial_cut)
557  count_1[net->getID()]++;
558  else
559  count_2[net->getID()]++;
560  if (count_1[net->getID()] > 0 && count_2[net->getID()] > 0) before_cuts++;
561  }
562  }
563 
564  // INITIAL GAIN CALCULATION
565  for(long id=0; id < m_design->cells.length(); id++)
566  if (target[id].loc > 0) {
567  assert(target[id].cell != 0);
568  assert(target[id].gain == 0);
569 
570  // examine counts for the net on each pin
571  for(ConcretePinMap::iterator p_it = target[id].cell->getPins().begin(); !p_it; p_it++)
572  if ((*p_it)->isAttached()) {
573  int n_id = (*p_it)->getNet()->getID();
574  if (target[id].loc == 1 && count_1[n_id] == 1) target[id].gain++;
575  if (target[id].loc == 1 && count_2[n_id] == 0) target[id].gain--;
576  if (target[id].loc == 2 && count_1[n_id] == 0) target[id].gain--;
577  if (target[id].loc == 2 && count_2[n_id] == 1) target[id].gain++;
578  }
579 
580  assert(target[id].cell->getPins().length() >= abs(target[id].gain));
581 
582  // add it to a bin
583  int bin_num = min(max(0, target[id].gain),FM_MAX_BIN);
584  max_gain = max(max_gain, bin_num);
585 
586  assert(bin_num >= 0 && bin_num <= FM_MAX_BIN);
587  target[id].next = bin[bin_num];
588  target[id].prev = 0;
589  if (bin[bin_num] != 0)
590  bin[bin_num]->prev = &target[id];
591  bin[bin_num] = &target[id];
592  }
593 
594  // OUTER F-M LOOP
595  current_cuts = before_cuts;
596  int num_moves = 1;
597  int pass = 0;
598  while(num_moves > 0 && pass < FM_MAX_PASSES) {
599  pass++;
600  num_moves = 0;
601 
602  // check_list(bin, locked, targets); // DEBUG
603 
604  // move all locked cells back
605  int moved_back = 0;
606  while(locked != 0) {
607  FM_cell *current = locked;
608  current->locked = false;
609 
610  int bin_num = min(max(0, current->gain),FM_MAX_BIN);
611  max_gain = max(max_gain, bin_num);
612 
613  locked = current->next;
614  if (locked != 0)
615  locked->prev = 0;
616 
617  if (bin[bin_num] != 0)
618  bin[bin_num]->prev = current;
619  current->next = bin[bin_num];
620  bin[bin_num] = current;
621 
622  moved_back++;
623  }
624  // cout << "\tmoved back: " << moved_back << endl;
625  // check_list(bin, locked, targets); // DEBUG
626 
627  max_gain = FM_MAX_BIN;
628  while(bin[max_gain] == 0 && max_gain > 0) max_gain--;
629 
630  // INNER F-M LOOP (single pass)
631  while(1) {
632 
633  int bin_num = FM_MAX_BIN;
634  FM_cell *current = bin[bin_num];
635 
636  // look for next cell to move
637  while (bin_num > 0 && (current == 0 ||
638  (current->loc==1 && current->cell->getArea()+parent->m_sub2->m_area > halfArea+areaFlexibility) ||
639  (current->loc==2 && current->cell->getArea()+parent->m_sub1->m_area > halfArea+areaFlexibility))) {
640 
641  if (current == 0) current = bin[--bin_num]; else current = current->next;
642  }
643  if (bin_num == 0)
644  break;
645 
646  num_moves++;
647  current->locked = true;
648  // cout << "moving cell " << current->cell->getID() << " gain=" << current->gain << " pins= " << current->cell->getPins().length() << " from " << current->loc;
649 
650  // change partition marking and areas
651  if (current->loc == 1) {
652  current->loc = 2;
653  parent->m_sub1->m_area -= current->cell->getArea();
654  parent->m_sub2->m_area += current->cell->getArea();
655 
656  // update partition counts on all nets attached to this cell
657  for(ConcretePinMap::iterator p_it = current->cell->getPins().begin();
658  !p_it; p_it++) {
659 
660  if (!(*p_it)->isAttached()) // ignore unattached pins
661  continue;
662  net = (*p_it)->getNet();
663 
664  count_1[net->getID()]--;
665  count_2[net->getID()]++;
666 
667  // cout << "\tnet " << net->getID() << " was " << count_1[net->getID()]+1 << "/" << count_2[net->getID()]-1 << " now " << count_1[net->getID()] << "/" << count_2[net->getID()] << endl;
668 
669  // if net becomes critical, update gains on attached cells and resort bins
670  if (count_1[net->getID()] == 0) { current_cuts--; FM_updateGains(net, 2, -1, target, bin, count_1, count_2); }
671  if (count_2[net->getID()] == 1) { current_cuts++; FM_updateGains(net, 1, -1, target, bin, count_1, count_2); }
672 
673  // check_list(bin, locked, targets); // DEBUG
674  }
675 
676  } else {
677  current->loc = 1;
678  parent->m_sub2->m_area -= current->cell->getArea();
679  parent->m_sub1->m_area += current->cell->getArea();
680 
681  // update gains on all nets attached to this cell
682  for(ConcretePinMap::iterator p_it = current->cell->getPins().begin();
683  !p_it; p_it++) {
684 
685  if (!(*p_it)->isAttached()) // ignore unattached pins
686  continue;
687  net = (*p_it)->getNet();
688  count_2[net->getID()]--;
689  count_1[net->getID()]++;
690 
691  // cout << "\tnet " << net->getID() << " was " << count_1[net->getID()]-1 << "/" << count_2[net->getID()]+1 << " now " << count_1[net->getID()] << "/" << count_2[net->getID()] << endl;
692 
693  if (count_2[net->getID()] == 0) { current_cuts--; FM_updateGains(net, 2, -1, target, bin, count_1, count_2); }
694  if (count_1[net->getID()] == 1) { current_cuts++; FM_updateGains(net, 1, -1, target, bin, count_1, count_2); }
695 
696  // check_list(bin, locked, targets); // DEBUG
697  }
698  }
699 
700  //cout << " cuts=" << current_cuts << endl;
701 
702  // move current to locked
703 
704 /*
705  cout << "b=" << bin[bin_num] << " ";
706  cout << current->prev << "-> ";
707  if (current->prev == 0)
708  cout << "X";
709  else cout << current->prev->next;
710  cout << "=" << current << "=";
711  if (current->next == 0)
712  cout << "X";
713  else
714  cout << current->next->prev;
715  cout << " ->" << current->next << endl;
716 */
717 
718  if (bin[bin_num] == current)
719  bin[bin_num] = current->next;
720  if (current->prev != 0)
721  current->prev->next = current->next;
722  if (current->next != 0)
723  current->next->prev = current->prev;
724 
725 /*
726  cout << "b=" << bin[bin_num] << " ";
727  cout << current->prev << "-> ";
728  if (current->prev == 0)
729  cout << "X";
730  else cout << current->prev->next;
731  cout << "=" << current << "=";
732  if (current->next == 0)
733  cout << "X";
734  else
735  cout << current->next->prev;
736  cout << " ->" << current->next << endl;
737 */
738 
739  current->prev = 0;
740  current->next = locked;
741  if (locked != 0)
742  locked->prev = current;
743  locked = current;
744 
745  // check_list(bin, locked, targets); // DEBUG
746 
747  // update max_gain
748  max_gain = FM_MAX_BIN;
749  while(bin[max_gain] == 0 && max_gain > 0) max_gain--;
750  }
751 
752  // cout << "\tcurrent cuts= " << current_cuts << " moves= " << num_moves << endl;
753  }
754 
755  // reassign members to subpartitions
756  cout << "FIDM-20 : \tbalance before " << parent->m_sub1->m_members.length() << "/"
757  << parent->m_sub2->m_members.length() << " ";
758  parent->m_sub1->m_members.clear();
759  parent->m_sub1->m_area = 0;
760  parent->m_sub2->m_members.clear();
761  parent->m_sub2->m_area = 0;
762  for(h::list<ConcreteCell *>::iterator it = parent->m_members.begin(); !it; it++) {
763  if (target[(*it)->getID()].loc == 1 || target[(*it)->getID()].loc == -1) {
764  parent->m_sub1->m_members.push_back(*it);
765  parent->m_sub1->m_area += (*it)->getArea();
766  }
767  else {
768  parent->m_sub2->m_members.push_back(*it);
769  parent->m_sub2->m_area += (*it)->getArea();
770  }
771  }
772  cout << " after " << parent->m_sub1->m_members.length() << "/"
773  << parent->m_sub2->m_members.length() << endl;
774 
775 
776  cout << "FIDM-21 : \tloc: " << initial_cut << " targetting: " << targets*100/parent->m_members.length() << "%" << endl;
777  cout << "FIDM-22 : \tstarting cuts= " << before_cuts << " final cuts= " << current_cuts << endl;
778 #endif
779 }
780 
781 // ----- FM_updateGains()
782 // moves a cell between bins
783 #if 0
784 void FM_updateGains(ConcreteNet *net, int partition, int inc,
785  FM_cell target [], FM_cell *bin [],
786  int count_1 [], int count_2 []) {
787 
788  for(ConcretePinList::iterator it = net->getPins().begin(); !it; it++) {
789  FM_cell *current = &(target[(*it)->getCell()->getID()]);
790  assert(current->cell != 0);
791 
792  int old_gain = current->gain;
793  current->gain = 0;
794 
795  // examine counts for the net on each pin
796  for(ConcretePinMap::iterator p_it = current->cell->getPins().begin(); !p_it; p_it++)
797  if ((*p_it)->isAttached()) {
798  int n_id = (*p_it)->getNet()->getID();
799  if (current->loc == 1 && count_1[n_id] == 1) current->gain++;
800  if (current->loc == 1 && count_2[n_id] == 0) current->gain--;
801  if (current->loc == 2 && count_1[n_id] == 0) current->gain--;
802  if (current->loc == 2 && count_2[n_id] == 1) current->gain++;
803  }
804 
805  if (!current->locked) {
806  // remove cell from existing bin
807  int bin_num = min(max(0, old_gain),FM_MAX_BIN);
808  if (bin[bin_num] == current)
809  bin[bin_num] = current->next;
810  if (current->prev != 0)
811  current->prev->next = current->next;
812  if (current->next != 0)
813  current->next->prev = current->prev;
814  // add cell to correct bin
815  bin_num = min(max(0, current->gain),FM_MAX_BIN);
816  current->prev = 0;
817  current->next = bin[bin_num];
818  if (bin[bin_num] != 0)
819  bin[bin_num]->prev = current;
820  bin[bin_num] = current;
821  }
822  }
823 
824 }
825 #endif
826 
827 
828 // --------------------------------------------------------------------
829 // partitionEqualArea()
830 //
831 /// \brief Splits a partition into two halves of equal area.
832 //
833 // --------------------------------------------------------------------
835  float halfArea, area;
836  int i=0;
837 
838  // which way to sort?
839  if (parent->m_vertical)
840  // sort by X position
841  qsort(parent->m_members, parent->m_numMembers, sizeof(ConcreteCell*), cellSortByX);
842  else
843  // sort by Y position
844  qsort(parent->m_members, parent->m_numMembers, sizeof(ConcreteCell*), cellSortByY);
845 
846  // split the list
847  halfArea = parent->m_area*0.5;
848  parent->m_sub1->m_area = 0.0;
849  parent->m_sub1->m_numMembers = 0;
850  parent->m_sub1->m_members = (ConcreteCell**)realloc(parent->m_sub1->m_members,
851  sizeof(ConcreteCell*)*parent->m_numMembers);
852  parent->m_sub2->m_area = 0.0;
853  parent->m_sub2->m_numMembers = 0;
854  parent->m_sub2->m_members = (ConcreteCell**)realloc(parent->m_sub2->m_members,
855  sizeof(ConcreteCell*)*parent->m_numMembers);
856 
857  for(; parent->m_sub1->m_area < halfArea; i++)
858  if (parent->m_members[i]) {
859  area = getCellArea(parent->m_members[i]);
860  parent->m_sub1->m_members[parent->m_sub1->m_numMembers++] = parent->m_members[i];
861  parent->m_sub1->m_area += area;
862  }
863  for(; i<parent->m_numMembers; i++)
864  if (parent->m_members[i]) {
865  area = getCellArea(parent->m_members[i]);
866  parent->m_sub2->m_members[parent->m_sub2->m_numMembers++] = parent->m_members[i];
867  parent->m_sub2->m_area += area;
868  }
869 
870 }
871 
872 
873 // --------------------------------------------------------------------
874 // partitionScanlineMincut()
875 //
876 /// \brief Scans the cells within a partition from left to right and chooses the min-cut.
877 //
878 // --------------------------------------------------------------------
880 #if 0
881  int current_cuts = 0;
882  int minimum_cuts = INT_MAX;
883  ConcreteCell *minimum_location = NULL;
884  double currentArea = 0, halfArea = parent->m_area * 0.5;
885  double areaFlexibility = parent->m_area * MAX_PARTITION_NONSYMMETRY;
886  double newLine, oldLine = -DBL_MAX;
887 
888  for(ConcreteNetList::iterator n_it = m_design->nets.begin(); !n_it; n_it++)
889  (*n_it)->m_mark = 0;
890  for(h::list<ConcreteCell *>::iterator i = parent->m_members.begin();
891  !i.isDone(); i++) {
892  assert(*i);
893  for(ConcretePinMap::iterator j = (*i)->getPins().begin();
894  !j.isDone(); j++) {
895  assert(*j);
896  if((*j)->isAttached()) {
897  (*j)->getNet()->m_mark = 1;
898  }
899  }
900  }
901 
902  if (parent->vertical) {
903  parent->m_members.sort(sortByX);
904  int all1 = 0, all2 = 0;
905  h::list<ConcreteCell *>::iterator local = parent->m_members.begin();
906  for(; !local.isDone(); local++) {
907  currentArea += (*local)->getArea();
908  if (currentArea < halfArea-areaFlexibility)
909  continue;
910  if (currentArea > halfArea+areaFlexibility)
911  break;
912  newLine = (*local)->temp_x;
913  while(all1 < g_place_numNets && allNetsL2[all1]->getBoundingBox().left() <= newLine) {
914  if(allNetsL2[all1]->m_mark) {
915  current_cuts++;
916  }
917  all1++;
918  }
919  while(all2 < g_place_numNets && allNetsR2[all2]->getBoundingBox().right() <= newLine) {
920  if(allNetsR2[all2]->m_mark) {
921  current_cuts--;
922  }
923  all2++;
924  }
925  if (current_cuts < minimum_cuts) {
926  minimum_cuts = current_cuts;
927  minimum_location = *local;
928  }
929  oldLine = newLine;
930  }
931  }
932  else {
933  parent->m_members.sort(sortByY);
934  int all1 = 0, all2 = 0;
935  h::list<ConcreteCell *>::iterator local = parent->m_members.begin();
936  for(; !local.isDone(); local++) {
937  currentArea += (*local)->getArea();
938  if (currentArea < halfArea-areaFlexibility)
939  continue;
940  if (currentArea > halfArea+areaFlexibility)
941  break;
942  newLine = (*local)->temp_y;
943  while(all1 < g_place_numNets && allNetsB2[all1]->getBoundingBox().top() <= newLine) {
944  if(allNetsB2[all1]->m_mark) {
945  current_cuts++;
946  }
947  all1++;
948  }
949  while(all2 < g_place_numNets && allNetsT2[all2]->getBoundingBox().bottom() <= newLine) {
950  if(allNetsT2[all2]->m_mark) {
951  current_cuts--;
952  }
953  all2++;
954  }
955  if (current_cuts < minimum_cuts) {
956  minimum_cuts = current_cuts;
957  minimum_location = *local;
958  }
959  oldLine = newLine;
960  }
961  }
962  if (minimum_location == NULL) {
963  return partitionEqualArea(parent);
964  }
965  h::list<ConcreteCell *>::iterator it = parent->m_members.begin();
966  parent->m_sub1->m_members.clear();
967  parent->m_sub1->m_area = 0;
968  for(; *it != minimum_location; it++) {
969  parent->m_sub1->m_members.push_front(*it);
970  parent->m_sub1->m_area += (*it)->getArea();
971  }
972  parent->m_sub2->m_members.clear();
973  parent->m_sub2->m_area = 0;
974  for(; !it; it++) {
975  parent->m_sub2->m_members.push_front(*it);
976  parent->m_sub2->m_area += (*it)->getArea();
977  }
978 #endif
979 }
980 
981 
982 // --------------------------------------------------------------------
983 // reallocPartition()
984 //
985 /// \brief Reallocates a partition and all of its children.
986 //
987 // --------------------------------------------------------------------
989 
990  if (p->m_leaf) {
991  return;
992  }
993 
994  // --- INITIAL PARTITION
995 
998  else
1000 
1001  resizePartition(p);
1002 
1003  // --- PARTITION IMPROVEMENT
1004  if (p->m_level < REPARTITION_LEVEL_DEPTH) {
1005  if (REPARTITION_HMETIS)
1006  repartitionHMetis(p);
1007 
1008  resizePartition(p);
1009  }
1010 
1013 }
1014 
1015 
1016 // --------------------------------------------------------------------
1017 // resizePartition()
1018 //
1019 /// \brief Recomputes the bounding boxes of the child partitions based on their relative areas.
1020 //
1021 // --------------------------------------------------------------------
1023  // compute the new bounding box
1024  p->m_sub1->m_bounds.x = p->m_bounds.x;
1025  p->m_sub1->m_bounds.y = p->m_bounds.y;
1026  if (p->m_vertical) {
1027  p->m_sub1->m_bounds.w = p->m_bounds.w*(p->m_sub1->m_area/p->m_area);
1028  p->m_sub1->m_bounds.h = p->m_bounds.h;
1029  p->m_sub2->m_bounds.x = p->m_bounds.x + p->m_sub1->m_bounds.w;
1030  p->m_sub2->m_bounds.w = p->m_bounds.w*(p->m_sub2->m_area/p->m_area);
1031  p->m_sub2->m_bounds.y = p->m_bounds.y;
1032  p->m_sub2->m_bounds.h = p->m_bounds.h;
1033  } else {
1034  p->m_sub1->m_bounds.h = p->m_bounds.h*(p->m_sub1->m_area/p->m_area);
1035  p->m_sub1->m_bounds.w = p->m_bounds.w;
1036  p->m_sub2->m_bounds.y = p->m_bounds.y + p->m_sub1->m_bounds.h;
1037  p->m_sub2->m_bounds.h = p->m_bounds.h*(p->m_sub2->m_area/p->m_area);
1038  p->m_sub2->m_bounds.x = p->m_bounds.x;
1039  p->m_sub2->m_bounds.w = p->m_bounds.w;
1040  }
1041 }
1042 
1043 
1044 // --------------------------------------------------------------------
1045 // incrementalSubpartition()
1046 //
1047 /// \brief Adds new cells to an existing partition. Partition sizes/locations are unchanged.
1048 ///
1049 /// The function recurses, adding new cells to appropriate subpartitions.
1050 //
1051 // --------------------------------------------------------------------
1052 void incrementalSubpartition(Partition *p, ConcreteCell *newCells [], const int numNewCells) {
1053  int c;
1054  ConcreteCell **newCells1 = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*numNewCells),
1055  **newCells2 = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*numNewCells);
1056  int numNewCells1 = 0, numNewCells2 = 0;
1057  float cut_loc;
1058 
1059  assert(p);
1060 
1061  // add new cells to partition list
1063  sizeof(ConcreteCell*)*(p->m_numMembers+numNewCells));
1064  memcpy(&(p->m_members[p->m_numMembers]), newCells, sizeof(ConcreteCell*)*numNewCells);
1065  p->m_numMembers += numNewCells;
1066 
1067  // if is a leaf partition, finished
1068  if (p->m_leaf) return;
1069 
1070  // split new cells into sub-partitions based on location
1071  if (p->m_vertical) {
1072  cut_loc = p->m_sub2->m_bounds.x;
1073  for(c=0; c<numNewCells; c++)
1074  if (newCells[c]->m_x < cut_loc)
1075  newCells1[numNewCells1++] = newCells[c];
1076  else
1077  newCells2[numNewCells2++] = newCells[c];
1078  } else {
1079  cut_loc = p->m_sub2->m_bounds.y;
1080  for(c=0; c<numNewCells; c++)
1081  if (newCells[c]->m_y < cut_loc)
1082  newCells1[numNewCells1++] = newCells[c];
1083  else
1084  newCells2[numNewCells2++] = newCells[c];
1085  }
1086 
1087  if (numNewCells1 > 0) incrementalSubpartition(p->m_sub1, newCells1, numNewCells1);
1088  if (numNewCells2 > 0) incrementalSubpartition(p->m_sub2, newCells2, numNewCells2);
1089 
1090  free(newCells1);
1091  free(newCells2);
1092 }
1093 
1094 
1095 // --------------------------------------------------------------------
1096 // incrementalPartition()
1097 //
1098 /// \brief Adds new cells to an existing partition. Partition sizes/locations are unchanged.
1099 ///
1100 /// The function recurses, adding new cells to appropriate subpartitions.
1101 //
1102 // --------------------------------------------------------------------
1104  int c = 0, c2 = 0;
1105  int numNewCells = 0;
1106  ConcreteCell **allCells = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*g_place_numCells),
1107  **newCells = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*g_place_numCells);
1108 
1109  assert(g_place_rootPartition);
1110 
1111  // update cell list of root partition
1113  qsort(allCells, g_place_numCells, sizeof(ConcreteCell*), cellSortByID);
1114  qsort(g_place_rootPartition->m_members, g_place_rootPartition->m_numMembers,
1115  sizeof(ConcreteCell*), cellSortByID);
1116 
1117  // scan sorted lists and collect cells not in partitions
1118  while(!allCells[c++]);
1119  while(!g_place_rootPartition->m_members[c2++]);
1120 
1121  for(; c<g_place_numCells; c++, c2++) {
1122  while(c2 < g_place_rootPartition->m_numMembers &&
1123  allCells[c]->m_id > g_place_rootPartition->m_members[c2]->m_id) c2++;
1124  while(c < g_place_numCells &&
1125  (c2 >= g_place_rootPartition->m_numMembers ||
1126  allCells[c]->m_id < g_place_rootPartition->m_members[c2]->m_id)) {
1127  // a new cell!
1128  newCells[numNewCells++] = allCells[c];
1129  c++;
1130  }
1131  }
1132 
1133  printf("QPRT-50 : \tincremental partitioning with %d new cells\n", numNewCells);
1134  if (numNewCells>0) incrementalSubpartition(g_place_rootPartition, newCells, numNewCells);
1135 
1136  free(allCells);
1137  free(newCells);
1138 }
1140 
char * memset()
void partitionEqualArea(Partition *parent)
Splits a partition into two halves of equal area.
int cellSortByX(const void *a, const void *b)
Sorts cells by either position coordinate.
Definition: place_base.c:314
struct Partition * m_sub1
Definition: place_gordian.h:56
char * malloc()
bool refinePartition(Partition *p)
Splits any large leaves within a partition.
ABC_NAMESPACE_IMPL_START int g_place_numPartitions
Definition: place_gordian.c:28
int cellSortByY(const void *a, const void *b)
Definition: place_base.c:326
ConcreteNet ** allNetsT2
static ABC_NAMESPACE_HEADER_START void HMETIS_PartRecursive(int nvtxs, int nhedges, int *vwgts, int *eptr, int *eind, int *hewgts, int nparts, int nbfactor, int *options, int *part, int *edgecnt)
Definition: libhmetis.h:10
VOID_HACK free()
ConcreteNet ** g_place_concreteNets
Definition: place_base.c:35
float h
Definition: place_base.h:36
float x
Definition: place_base.h:35
static Llb_Mgr_t * p
Definition: llb3Image.c:950
int netSortByR(const void *a, const void *b)
Definition: place_base.c:249
#define FM_MAX_PASSES
Definition: place_gordian.h:40
void partitionScanlineMincut(Partition *parent)
Scans the cells within a partition from left to right and chooses the min-cut.
struct FM_cell * next
#define MAX_PARTITION_NONSYMMETRY
Definition: place_gordian.h:30
void resizePartition(Partition *p)
Recomputes the bounding boxes of the child partitions based on their relative areas.
int netSortByB(const void *a, const void *b)
Definition: place_base.c:263
char * memcpy()
struct FM_cell FM_cell
float y
Definition: place_base.h:35
ConcreteCell ** g_place_concreteCells
Definition: place_base.c:33
char * realloc()
void reallocPartitions()
Reallocates the partitions based on placement information.
ConcreteNet ** allNetsR2
struct Partition * m_sub2
Definition: place_gordian.h:56
ABC_NAMESPACE_IMPL_START Partition * g_place_rootPartition
#define FM_MAX_BIN
Definition: place_gordian.h:39
float getCellArea(const ConcreteCell *cell)
Definition: place_base.c:99
void reallocPartition(Partition *p)
Reallocates a partition and all of its children.
#define REPARTITION_HMETIS
Definition: place_gordian.h:36
void incrementalSubpartition(Partition *p, ConcreteCell *newCells[], const int numNewCells)
Adds new cells to an existing partition. Partition sizes/locations are unchanged. ...
void presortNets()
Sorts nets by corner positions.
ConcreteNet ** allNetsL2
bool m_vertical
Definition: place_gordian.h:51
int netSortByT(const void *a, const void *b)
Definition: place_base.c:277
ConcreteNet ** allNetsB2
static int partition(int *a, int n, int m)
Definition: abcSaucy.c:373
#define ABC_NAMESPACE_IMPL_END
Definition: abc_global.h:108
#define REPARTITION_FM
Definition: place_gordian.h:35
#define local
Definition: adler32.c:17
static double max
Definition: cuddSubsetHB.c:134
int cellSortByID(const void *a, const void *b)
Definition: place_base.c:338
void FM_updateGains(ConcreteNet *net, int partition, int inc, FM_cell target[], FM_cell *bin[], int count_1[], int count_2[])
void repartitionHMetis(Partition *parent)
Repartitions the two subpartitions using the hMetis min-cut library.
void repartitionFM(Partition *parent)
Fiduccia-Matheyses mincut partitioning algorithm.
ConcreteCell ** m_members
Definition: place_gordian.h:49
int m_numTerms
Definition: place_base.h:71
Rect g_place_coreBounds
Definition: place_base.c:30
#define ABC_NAMESPACE_IMPL_START
Definition: abc_global.h:107
float w
Definition: place_base.h:36
int g_place_numNets
Definition: place_base.c:27
#define REPARTITION_TARGET_FRACTION
Definition: place_gordian.h:34
#define LARGEST_FINAL_SIZE
Definition: place_gordian.h:25
void incrementalPartition()
Adds new cells to an existing partition. Partition sizes/locations are unchanged. ...
char * calloc()
#define REPARTITION_LEVEL_DEPTH
Definition: place_gordian.h:33
Rect m_bounds
Definition: place_gordian.h:50
int m_numMembers
Definition: place_gordian.h:48
#define assert(ex)
Definition: util_old.h:213
ABC_NAMESPACE_IMPL_START int g_place_numCells
Definition: place_base.c:26
ConcreteCell * cell
void initPartitioning()
Initializes data structures necessary for partitioning.
bool refinePartitions()
Splits large leaf partitions.
#define PARTITION_AREA_ONLY
Definition: place_gordian.h:26
struct FM_cell * prev
int netSortByL(const void *a, const void *b)
Sorts nets by position of one of its corners.
Definition: place_base.c:235
float m_area
Definition: place_gordian.h:54