1141 lines
37 KiB
C
1141 lines
37 KiB
C
/*===================================================================*/
|
|
//
|
|
// place_partition.c
|
|
//
|
|
// Aaron P. Hurst, 2003-2007
|
|
// ahurst@eecs.berkeley.edu
|
|
//
|
|
/*===================================================================*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <assert.h>
|
|
//#include <sys/stat.h>
|
|
//#include <unistd.h>
|
|
|
|
#include "place_base.h"
|
|
#include "place_gordian.h"
|
|
|
|
#if !defined(NO_HMETIS)
|
|
#include "libhmetis.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------
|
|
// Global variables
|
|
//
|
|
// --------------------------------------------------------------------
|
|
|
|
Partition *g_place_rootPartition = NULL;
|
|
ConcreteNet **allNetsR2 = NULL,
|
|
**allNetsL2 = NULL,
|
|
**allNetsB2 = NULL,
|
|
**allNetsT2 = NULL;
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// Function prototypes and local data structures
|
|
//
|
|
// --------------------------------------------------------------------
|
|
|
|
typedef struct FM_cell {
|
|
int loc;
|
|
int gain;
|
|
ConcreteCell *cell;
|
|
struct FM_cell *next, *prev;
|
|
bool locked;
|
|
} FM_cell;
|
|
|
|
void FM_updateGains(ConcreteNet *net, int partition, int inc,
|
|
FM_cell target [], FM_cell *bin [],
|
|
int count_1 [], int count_2 []);
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// initPartitioning()
|
|
//
|
|
/// \brief Initializes data structures necessary for partitioning.
|
|
//
|
|
/// Creates a valid g_place_rootPartition.
|
|
///
|
|
// --------------------------------------------------------------------
|
|
void initPartitioning() {
|
|
int i;
|
|
float area;
|
|
|
|
// create root partition
|
|
g_place_numPartitions = 1;
|
|
if (g_place_rootPartition) free(g_place_rootPartition);
|
|
g_place_rootPartition = malloc(sizeof(Partition));
|
|
g_place_rootPartition->m_level = 0;
|
|
g_place_rootPartition->m_area = 0;
|
|
g_place_rootPartition->m_bounds = g_place_coreBounds;
|
|
g_place_rootPartition->m_vertical = false;
|
|
g_place_rootPartition->m_done = false;
|
|
g_place_rootPartition->m_leaf = true;
|
|
|
|
// add all of the cells to this partition
|
|
g_place_rootPartition->m_members = malloc(sizeof(ConcreteCell*)*g_place_numCells);
|
|
g_place_rootPartition->m_numMembers = 0;
|
|
for (i=0; i<g_place_numCells; i++)
|
|
if (g_place_concreteCells[i]) {
|
|
if (!g_place_concreteCells[i]->m_fixed) {
|
|
area = getCellArea(g_place_concreteCells[i]);
|
|
g_place_rootPartition->m_members[g_place_rootPartition->m_numMembers++] =
|
|
g_place_concreteCells[i];
|
|
g_place_rootPartition->m_area += area;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// presortNets()
|
|
//
|
|
/// \brief Sorts nets by corner positions.
|
|
//
|
|
/// Allocates allNetsX2 structures.
|
|
///
|
|
// --------------------------------------------------------------------
|
|
void presortNets() {
|
|
allNetsL2 = (ConcreteNet**)realloc(allNetsL2, sizeof(ConcreteNet*)*g_place_numNets);
|
|
allNetsR2 = (ConcreteNet**)realloc(allNetsR2, sizeof(ConcreteNet*)*g_place_numNets);
|
|
allNetsB2 = (ConcreteNet**)realloc(allNetsB2, sizeof(ConcreteNet*)*g_place_numNets);
|
|
allNetsT2 = (ConcreteNet**)realloc(allNetsT2, sizeof(ConcreteNet*)*g_place_numNets);
|
|
memcpy(allNetsL2, g_place_concreteNets, sizeof(ConcreteNet*)*g_place_numNets);
|
|
memcpy(allNetsR2, g_place_concreteNets, sizeof(ConcreteNet*)*g_place_numNets);
|
|
memcpy(allNetsB2, g_place_concreteNets, sizeof(ConcreteNet*)*g_place_numNets);
|
|
memcpy(allNetsT2, g_place_concreteNets, sizeof(ConcreteNet*)*g_place_numNets);
|
|
qsort(allNetsL2, g_place_numNets, sizeof(ConcreteNet*), netSortByL);
|
|
qsort(allNetsR2, g_place_numNets, sizeof(ConcreteNet*), netSortByR);
|
|
qsort(allNetsB2, g_place_numNets, sizeof(ConcreteNet*), netSortByB);
|
|
qsort(allNetsT2, g_place_numNets, sizeof(ConcreteNet*), netSortByT);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// refinePartitions()
|
|
//
|
|
/// \brief Splits large leaf partitions.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
bool refinePartitions() {
|
|
|
|
return refinePartition(g_place_rootPartition);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// reallocPartitions()
|
|
//
|
|
/// \brief Reallocates the partitions based on placement information.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void reallocPartitions() {
|
|
|
|
reallocPartition(g_place_rootPartition);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// refinePartition()
|
|
//
|
|
/// \brief Splits any large leaves within a partition.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
bool refinePartition(Partition *p) {
|
|
bool degenerate = false;
|
|
int nonzeroCount = 0;
|
|
int i;
|
|
|
|
assert(p);
|
|
|
|
// is this partition completed?
|
|
if (p->m_done) return true;
|
|
|
|
// is this partition a non-leaf node?
|
|
if (!p->m_leaf) {
|
|
p->m_done = refinePartition(p->m_sub1);
|
|
p->m_done &= refinePartition(p->m_sub2);
|
|
return p->m_done;
|
|
}
|
|
|
|
// leaf...
|
|
// create two new subpartitions
|
|
g_place_numPartitions++;
|
|
p->m_sub1 = malloc(sizeof(Partition));
|
|
p->m_sub1->m_level = p->m_level+1;
|
|
p->m_sub1->m_leaf = true;
|
|
p->m_sub1->m_done = false;
|
|
p->m_sub1->m_area = 0;
|
|
p->m_sub1->m_vertical = !p->m_vertical;
|
|
p->m_sub1->m_numMembers = 0;
|
|
p->m_sub1->m_members = NULL;
|
|
p->m_sub2 = malloc(sizeof(Partition));
|
|
p->m_sub2->m_level = p->m_level+1;
|
|
p->m_sub2->m_leaf = true;
|
|
p->m_sub2->m_done = false;
|
|
p->m_sub2->m_area = 0;
|
|
p->m_sub2->m_vertical = !p->m_vertical;
|
|
p->m_sub2->m_numMembers = 0;
|
|
p->m_sub2->m_members = NULL;
|
|
p->m_leaf = false;
|
|
|
|
// --- INITIAL PARTITION
|
|
|
|
if (PARTITION_AREA_ONLY)
|
|
partitionEqualArea(p);
|
|
else
|
|
partitionScanlineMincut(p);
|
|
|
|
resizePartition(p);
|
|
|
|
// --- PARTITION IMPROVEMENT
|
|
|
|
if (p->m_level < REPARTITION_LEVEL_DEPTH) {
|
|
if (REPARTITION_FM)
|
|
repartitionFM(p);
|
|
else if (REPARTITION_HMETIS)
|
|
repartitionHMetis(p);
|
|
}
|
|
|
|
resizePartition(p);
|
|
|
|
// fix imbalances due to zero-area cells
|
|
for(i=0; i<p->m_sub1->m_numMembers; i++)
|
|
if (p->m_sub1->m_members[i])
|
|
if (getCellArea(p->m_sub1->m_members[i]) > 0) {
|
|
nonzeroCount++;
|
|
}
|
|
|
|
// is this leaf now done?
|
|
if (nonzeroCount <= LARGEST_FINAL_SIZE)
|
|
p->m_sub1->m_done = true;
|
|
if (nonzeroCount == 0)
|
|
degenerate = true;
|
|
|
|
nonzeroCount = 0;
|
|
for(i=0; i<p->m_sub2->m_numMembers; i++)
|
|
if (p->m_sub2->m_members[i])
|
|
if (getCellArea(p->m_sub2->m_members[i]) > 0) {
|
|
nonzeroCount++;
|
|
}
|
|
|
|
// is this leaf now done?
|
|
if (nonzeroCount <= LARGEST_FINAL_SIZE)
|
|
p->m_sub2->m_done = true;
|
|
if (nonzeroCount == 0)
|
|
degenerate = true;
|
|
|
|
// have we found a degenerate partitioning?
|
|
if (degenerate) {
|
|
printf("QPART-35 : WARNING: degenerate partition generated\n");
|
|
partitionEqualArea(p);
|
|
resizePartition(p);
|
|
p->m_sub1->m_done = true;
|
|
p->m_sub2->m_done = true;
|
|
}
|
|
|
|
// is this parent now finished?
|
|
if (p->m_sub1->m_done && p->m_sub2->m_done) p->m_done = true;
|
|
|
|
return p->m_done;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// repartitionHMetis()
|
|
//
|
|
/// \brief Repartitions the two subpartitions using the hMetis min-cut library.
|
|
///
|
|
/// The number of cut nets between the two partitions will be minimized.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void repartitionHMetis(Partition *parent) {
|
|
#if defined(NO_HMETIS)
|
|
printf("QPAR_02 : \t\tERROR: hMetis not available. Ignoring.\n");
|
|
#else
|
|
|
|
int n,c,t, i;
|
|
float area;
|
|
int *edgeConnections = NULL;
|
|
int *partitionAssignment = (int *)calloc(g_place_numCells, sizeof(int));
|
|
int *vertexWeights = (int *)calloc(g_place_numCells, sizeof(int));
|
|
int *edgeDegree = (int *)malloc(sizeof(int)*(g_place_numNets+1));
|
|
int numConnections = 0;
|
|
int numEdges = 0;
|
|
float initial_cut;
|
|
int targets = 0;
|
|
ConcreteCell *cell = NULL;
|
|
int options[9];
|
|
int afterCuts = 0;
|
|
|
|
assert(parent);
|
|
assert(parent->m_sub1);
|
|
assert(parent->m_sub2);
|
|
|
|
printf("QPAR-02 : \t\trepartitioning with hMetis\n");
|
|
|
|
// count edges
|
|
edgeDegree[0] = 0;
|
|
for(n=0; n<g_place_numNets; n++) if (g_place_concreteNets[n])
|
|
if (g_place_concreteNets[n]->m_numTerms > 1) {
|
|
numConnections += g_place_concreteNets[n]->m_numTerms;
|
|
edgeDegree[++numEdges] = numConnections;
|
|
}
|
|
|
|
if (parent->m_vertical) {
|
|
// vertical
|
|
initial_cut = parent->m_sub2->m_bounds.x;
|
|
|
|
// initialize all cells
|
|
for(c=0; c<g_place_numCells; c++) if (g_place_concreteCells[c]) {
|
|
if (g_place_concreteCells[c]->m_x < initial_cut)
|
|
partitionAssignment[c] = 0;
|
|
else
|
|
partitionAssignment[c] = 1;
|
|
}
|
|
|
|
// initialize cells in partition 1
|
|
for(t=0; t<parent->m_sub1->m_numMembers; t++) if (parent->m_sub1->m_members[t]) {
|
|
cell = parent->m_sub1->m_members[t];
|
|
vertexWeights[cell->m_id] = getCellArea(cell);
|
|
// pay attention to cells that are close to the cut
|
|
if (abs(cell->m_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
partitionAssignment[cell->m_id] = -1;
|
|
}
|
|
}
|
|
|
|
// initialize cells in partition 2
|
|
for(t=0; t<parent->m_sub2->m_numMembers; t++) if (parent->m_sub2->m_members[t]) {
|
|
cell = parent->m_sub2->m_members[t];
|
|
vertexWeights[cell->m_id] = getCellArea(cell);
|
|
// pay attention to cells that are close to the cut
|
|
if (abs(cell->m_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
partitionAssignment[cell->m_id] = -1;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// horizontal
|
|
initial_cut = parent->m_sub2->m_bounds.y;
|
|
|
|
// initialize all cells
|
|
for(c=0; c<g_place_numCells; c++) if (g_place_concreteCells[c]) {
|
|
if (g_place_concreteCells[c]->m_y < initial_cut)
|
|
partitionAssignment[c] = 0;
|
|
else
|
|
partitionAssignment[c] = 1;
|
|
}
|
|
|
|
// initialize cells in partition 1
|
|
for(t=0; t<parent->m_sub1->m_numMembers; t++) if (parent->m_sub1->m_members[t]) {
|
|
cell = parent->m_sub1->m_members[t];
|
|
vertexWeights[cell->m_id] = getCellArea(cell);
|
|
// pay attention to cells that are close to the cut
|
|
if (abs(cell->m_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
partitionAssignment[cell->m_id] = -1;
|
|
}
|
|
}
|
|
|
|
// initialize cells in partition 2
|
|
for(t=0; t<parent->m_sub2->m_numMembers; t++) if (parent->m_sub2->m_members[t]) {
|
|
cell = parent->m_sub2->m_members[t];
|
|
vertexWeights[cell->m_id] = getCellArea(cell);
|
|
// pay attention to cells that are close to the cut
|
|
if (abs(cell->m_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
partitionAssignment[cell->m_id] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
options[0] = 1; // any non-default values?
|
|
options[1] = 3; // num bisections
|
|
options[2] = 1; // grouping scheme
|
|
options[3] = 1; // refinement scheme
|
|
options[4] = 1; // cycle refinement scheme
|
|
options[5] = 0; // reconstruction scheme
|
|
options[6] = 0; // fixed assignments?
|
|
options[7] = 12261980; // random seed
|
|
options[8] = 0; // debugging level
|
|
|
|
edgeConnections = (int *)malloc(sizeof(int)*numConnections);
|
|
|
|
i = 0;
|
|
for(n=0; n<g_place_numNets; n++) if (g_place_concreteNets[n]) {
|
|
if (g_place_concreteNets[n]->m_numTerms > 1)
|
|
for(t=0; t<g_place_concreteNets[n]->m_numTerms; t++)
|
|
edgeConnections[i++] = g_place_concreteNets[n]->m_terms[t]->m_id;
|
|
}
|
|
|
|
HMETIS_PartRecursive(g_place_numCells, numEdges, vertexWeights,
|
|
edgeDegree, edgeConnections, NULL,
|
|
2, (int)(100*MAX_PARTITION_NONSYMMETRY),
|
|
options, partitionAssignment, &afterCuts);
|
|
|
|
/*
|
|
printf("HMET-20 : \t\t\tbalance before %d / %d ... ", parent->m_sub1->m_numMembers,
|
|
parent->m_sub2->m_numMembers);
|
|
*/
|
|
|
|
// reassign members to subpartitions
|
|
parent->m_sub1->m_numMembers = 0;
|
|
parent->m_sub1->m_area = 0;
|
|
parent->m_sub2->m_numMembers = 0;
|
|
parent->m_sub2->m_area = 0;
|
|
parent->m_sub1->m_members = (ConcreteCell**)realloc(parent->m_sub1->m_members,
|
|
sizeof(ConcreteCell*)*parent->m_numMembers);
|
|
parent->m_sub2->m_members = (ConcreteCell**)realloc(parent->m_sub2->m_members,
|
|
sizeof(ConcreteCell*)*parent->m_numMembers);
|
|
|
|
for(t=0; t<parent->m_numMembers; t++) if (parent->m_members[t]) {
|
|
cell = parent->m_members[t];
|
|
area = getCellArea(cell);
|
|
if (partitionAssignment[cell->m_id] == 0) {
|
|
parent->m_sub1->m_members[parent->m_sub1->m_numMembers++] = cell;
|
|
parent->m_sub1->m_area += area;
|
|
}
|
|
else {
|
|
parent->m_sub2->m_members[parent->m_sub2->m_numMembers++] = cell;
|
|
parent->m_sub2->m_area += area;
|
|
}
|
|
}
|
|
/*
|
|
printf("after %d / %d\n", parent->m_sub1->m_numMembers,
|
|
parent->m_sub2->m_numMembers);
|
|
*/
|
|
|
|
// cout << "HMET-21 : \t\t\tloc: " << initial_cut << " targetting: " << targets*100/parent->m_members.length() << "%" << endl;
|
|
// cout << "HMET-22 : \t\t\tstarting cuts= " << beforeCuts << " final cuts= " << afterCuts << endl;
|
|
|
|
free(edgeConnections);
|
|
free(vertexWeights);
|
|
free(edgeDegree);
|
|
free(partitionAssignment);
|
|
#endif
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// repartitionFM()
|
|
//
|
|
/// \brief Fiduccia-Matheyses mincut partitioning algorithm.
|
|
//
|
|
/// UNIMPLEMENTED (well, un-C-ified)
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void repartitionFM(Partition *parent) {
|
|
#if 0
|
|
assert(!parent->leaf && parent->m_sub1->leaf && parent->m_sub2->leaf);
|
|
|
|
// count of each net's number of cells in each bipartition
|
|
int count_1[m_design->nets.length()];
|
|
memset(count_1, 0, sizeof(int)*m_design->nets.length());
|
|
int count_2[m_design->nets.length()];
|
|
memset(count_2, 0, sizeof(int)*m_design->nets.length());
|
|
|
|
FM_cell target[m_design->cells.length()];
|
|
memset(target, 0, sizeof(FM_cell)*m_design->cells.length());
|
|
FM_cell *bin[FM_MAX_BIN+1];
|
|
FM_cell *locked = 0;
|
|
memset(bin, 0, sizeof(FM_cell *)*(FM_MAX_BIN+1));
|
|
|
|
int max_gain = 0;
|
|
int before_cuts = 0, current_cuts = 0;
|
|
double initial_cut;
|
|
int targets = 0;
|
|
long cell_id;
|
|
double halfArea = parent->m_area / 2.0;
|
|
double areaFlexibility = parent->m_area * MAX_PARTITION_NONSYMMETRY;
|
|
ConcreteNet *net;
|
|
|
|
// INITIALIZATION
|
|
// select cells to partition
|
|
|
|
if (parent->vertical) {
|
|
// vertical
|
|
|
|
initial_cut = parent->m_sub2->m_bounds.x;
|
|
|
|
// initialize all cells
|
|
for(h::list<ConcreteCell *>::iterator it = rootPartition->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
if ((*it)->temp_x < initial_cut)
|
|
target[cell_id].loc = -1;
|
|
else
|
|
target[cell_id].loc = -2;
|
|
target[cell_id].cell = *it;
|
|
target[cell_id].gain = 0;
|
|
}
|
|
|
|
// initialize cells in partition 1
|
|
for(h::list<ConcreteCell *>::iterator it = parent->m_sub1->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
// pay attention to cells that are close to the cut
|
|
if (abs((*it)->temp_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
target[cell_id].loc = 1;
|
|
}
|
|
}
|
|
|
|
// initialize cells in partition 2
|
|
for(h::list<ConcreteCell *>::iterator it = parent->m_sub2->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
// pay attention to cells that are close to the cut
|
|
if (abs((*it)->temp_x-initial_cut) < parent->m_bounds.w*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
target[cell_id].loc = 2;
|
|
}
|
|
}
|
|
|
|
// count the number of cells on each side of the partition for every net
|
|
for(h::hash_map<ConcreteNet *>::iterator n_it = m_design->nets.begin(); !n_it; n_it++) {
|
|
for(ConcretePinList::iterator p_it = (net = *n_it)->getPins().begin(); !p_it; p_it++)
|
|
if (abs(target[(*p_it)->getCell()->getID()].loc) == 1)
|
|
count_1[net->getID()]++;
|
|
else if (abs(target[(*p_it)->getCell()->getID()].loc) == 2)
|
|
count_2[net->getID()]++;
|
|
else if ((*p_it)->getCell()->temp_x < initial_cut)
|
|
count_1[net->getID()]++;
|
|
else
|
|
count_2[net->getID()]++;
|
|
if (count_1[net->getID()] > 0 && count_2[net->getID()] > 0) before_cuts++;
|
|
}
|
|
|
|
} else {
|
|
// horizontal
|
|
|
|
initial_cut = parent->m_sub2->m_bounds.y;
|
|
|
|
// initialize all cells
|
|
for(h::list<ConcreteCell *>::iterator it = rootPartition->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
if ((*it)->temp_y < initial_cut)
|
|
target[cell_id].loc = -1;
|
|
else
|
|
target[cell_id].loc = -2;
|
|
target[cell_id].cell = *it;
|
|
target[cell_id].gain = 0;
|
|
}
|
|
|
|
// initialize cells in partition 1
|
|
for(h::list<ConcreteCell *>::iterator it = parent->m_sub1->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
// pay attention to cells that are close to the cut
|
|
if (abs((*it)->temp_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
target[cell_id].loc = 1;
|
|
}
|
|
}
|
|
|
|
// initialize cells in partition 2
|
|
for(h::list<ConcreteCell *>::iterator it = parent->m_sub2->m_members.begin(); !it; it++) {
|
|
cell_id = (*it)->getID();
|
|
// pay attention to cells that are close to the cut
|
|
if (abs((*it)->temp_y-initial_cut) < parent->m_bounds.h*REPARTITION_TARGET_FRACTION) {
|
|
targets++;
|
|
target[cell_id].loc = 2;
|
|
}
|
|
}
|
|
|
|
// count the number of cells on each side of the partition for every net
|
|
for(h::hash_map<ConcreteNet *>::iterator n_it = m_design->nets.begin(); !n_it; n_it++) {
|
|
for(ConcretePinList::iterator p_it = (net = *n_it)->getPins().begin(); !p_it; p_it++)
|
|
if (abs(target[(*p_it)->getCell()->getID()].loc) == 1)
|
|
count_1[net->getID()]++;
|
|
else if (abs(target[(*p_it)->getCell()->getID()].loc) == 2)
|
|
count_2[net->getID()]++;
|
|
else if ((*p_it)->getCell()->temp_y < initial_cut)
|
|
count_1[net->getID()]++;
|
|
else
|
|
count_2[net->getID()]++;
|
|
if (count_1[net->getID()] > 0 && count_2[net->getID()] > 0) before_cuts++;
|
|
}
|
|
}
|
|
|
|
// INITIAL GAIN CALCULATION
|
|
for(long id=0; id < m_design->cells.length(); id++)
|
|
if (target[id].loc > 0) {
|
|
assert(target[id].cell != 0);
|
|
assert(target[id].gain == 0);
|
|
|
|
// examine counts for the net on each pin
|
|
for(ConcretePinMap::iterator p_it = target[id].cell->getPins().begin(); !p_it; p_it++)
|
|
if ((*p_it)->isAttached()) {
|
|
int n_id = (*p_it)->getNet()->getID();
|
|
if (target[id].loc == 1 && count_1[n_id] == 1) target[id].gain++;
|
|
if (target[id].loc == 1 && count_2[n_id] == 0) target[id].gain--;
|
|
if (target[id].loc == 2 && count_1[n_id] == 0) target[id].gain--;
|
|
if (target[id].loc == 2 && count_2[n_id] == 1) target[id].gain++;
|
|
}
|
|
|
|
assert(target[id].cell->getPins().length() >= abs(target[id].gain));
|
|
|
|
// add it to a bin
|
|
int bin_num = min(max(0, target[id].gain),FM_MAX_BIN);
|
|
max_gain = max(max_gain, bin_num);
|
|
|
|
assert(bin_num >= 0 && bin_num <= FM_MAX_BIN);
|
|
target[id].next = bin[bin_num];
|
|
target[id].prev = 0;
|
|
if (bin[bin_num] != 0)
|
|
bin[bin_num]->prev = &target[id];
|
|
bin[bin_num] = &target[id];
|
|
}
|
|
|
|
// OUTER F-M LOOP
|
|
current_cuts = before_cuts;
|
|
int num_moves = 1;
|
|
int pass = 0;
|
|
while(num_moves > 0 && pass < FM_MAX_PASSES) {
|
|
pass++;
|
|
num_moves = 0;
|
|
|
|
// check_list(bin, locked, targets); // DEBUG
|
|
|
|
// move all locked cells back
|
|
int moved_back = 0;
|
|
while(locked != 0) {
|
|
FM_cell *current = locked;
|
|
current->locked = false;
|
|
|
|
int bin_num = min(max(0, current->gain),FM_MAX_BIN);
|
|
max_gain = max(max_gain, bin_num);
|
|
|
|
locked = current->next;
|
|
if (locked != 0)
|
|
locked->prev = 0;
|
|
|
|
if (bin[bin_num] != 0)
|
|
bin[bin_num]->prev = current;
|
|
current->next = bin[bin_num];
|
|
bin[bin_num] = current;
|
|
|
|
moved_back++;
|
|
}
|
|
// cout << "\tmoved back: " << moved_back << endl;
|
|
// check_list(bin, locked, targets); // DEBUG
|
|
|
|
max_gain = FM_MAX_BIN;
|
|
while(bin[max_gain] == 0 && max_gain > 0) max_gain--;
|
|
|
|
// INNER F-M LOOP (single pass)
|
|
while(1) {
|
|
|
|
int bin_num = FM_MAX_BIN;
|
|
FM_cell *current = bin[bin_num];
|
|
|
|
// look for next cell to move
|
|
while (bin_num > 0 && (current == 0 ||
|
|
(current->loc==1 && current->cell->getArea()+parent->m_sub2->m_area > halfArea+areaFlexibility) ||
|
|
(current->loc==2 && current->cell->getArea()+parent->m_sub1->m_area > halfArea+areaFlexibility))) {
|
|
|
|
if (current == 0) current = bin[--bin_num]; else current = current->next;
|
|
}
|
|
if (bin_num == 0)
|
|
break;
|
|
|
|
num_moves++;
|
|
current->locked = true;
|
|
// cout << "moving cell " << current->cell->getID() << " gain=" << current->gain << " pins= " << current->cell->getPins().length() << " from " << current->loc;
|
|
|
|
// change partition marking and areas
|
|
if (current->loc == 1) {
|
|
current->loc = 2;
|
|
parent->m_sub1->m_area -= current->cell->getArea();
|
|
parent->m_sub2->m_area += current->cell->getArea();
|
|
|
|
// update partition counts on all nets attached to this cell
|
|
for(ConcretePinMap::iterator p_it = current->cell->getPins().begin();
|
|
!p_it; p_it++) {
|
|
|
|
if (!(*p_it)->isAttached()) // ignore unattached pins
|
|
continue;
|
|
net = (*p_it)->getNet();
|
|
|
|
count_1[net->getID()]--;
|
|
count_2[net->getID()]++;
|
|
|
|
// 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;
|
|
|
|
// if net becomes critical, update gains on attached cells and resort bins
|
|
if (count_1[net->getID()] == 0) { current_cuts--; FM_updateGains(net, 2, -1, target, bin, count_1, count_2); }
|
|
if (count_2[net->getID()] == 1) { current_cuts++; FM_updateGains(net, 1, -1, target, bin, count_1, count_2); }
|
|
|
|
// check_list(bin, locked, targets); // DEBUG
|
|
}
|
|
|
|
} else {
|
|
current->loc = 1;
|
|
parent->m_sub2->m_area -= current->cell->getArea();
|
|
parent->m_sub1->m_area += current->cell->getArea();
|
|
|
|
// update gains on all nets attached to this cell
|
|
for(ConcretePinMap::iterator p_it = current->cell->getPins().begin();
|
|
!p_it; p_it++) {
|
|
|
|
if (!(*p_it)->isAttached()) // ignore unattached pins
|
|
continue;
|
|
net = (*p_it)->getNet();
|
|
count_2[net->getID()]--;
|
|
count_1[net->getID()]++;
|
|
|
|
// 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;
|
|
|
|
if (count_2[net->getID()] == 0) { current_cuts--; FM_updateGains(net, 2, -1, target, bin, count_1, count_2); }
|
|
if (count_1[net->getID()] == 1) { current_cuts++; FM_updateGains(net, 1, -1, target, bin, count_1, count_2); }
|
|
|
|
// check_list(bin, locked, targets); // DEBUG
|
|
}
|
|
}
|
|
|
|
//cout << " cuts=" << current_cuts << endl;
|
|
|
|
// move current to locked
|
|
|
|
/*
|
|
cout << "b=" << bin[bin_num] << " ";
|
|
cout << current->prev << "-> ";
|
|
if (current->prev == 0)
|
|
cout << "X";
|
|
else cout << current->prev->next;
|
|
cout << "=" << current << "=";
|
|
if (current->next == 0)
|
|
cout << "X";
|
|
else
|
|
cout << current->next->prev;
|
|
cout << " ->" << current->next << endl;
|
|
*/
|
|
|
|
if (bin[bin_num] == current)
|
|
bin[bin_num] = current->next;
|
|
if (current->prev != 0)
|
|
current->prev->next = current->next;
|
|
if (current->next != 0)
|
|
current->next->prev = current->prev;
|
|
|
|
/*
|
|
cout << "b=" << bin[bin_num] << " ";
|
|
cout << current->prev << "-> ";
|
|
if (current->prev == 0)
|
|
cout << "X";
|
|
else cout << current->prev->next;
|
|
cout << "=" << current << "=";
|
|
if (current->next == 0)
|
|
cout << "X";
|
|
else
|
|
cout << current->next->prev;
|
|
cout << " ->" << current->next << endl;
|
|
*/
|
|
|
|
current->prev = 0;
|
|
current->next = locked;
|
|
if (locked != 0)
|
|
locked->prev = current;
|
|
locked = current;
|
|
|
|
// check_list(bin, locked, targets); // DEBUG
|
|
|
|
// update max_gain
|
|
max_gain = FM_MAX_BIN;
|
|
while(bin[max_gain] == 0 && max_gain > 0) max_gain--;
|
|
}
|
|
|
|
// cout << "\tcurrent cuts= " << current_cuts << " moves= " << num_moves << endl;
|
|
}
|
|
|
|
// reassign members to subpartitions
|
|
cout << "FIDM-20 : \tbalance before " << parent->m_sub1->m_members.length() << "/"
|
|
<< parent->m_sub2->m_members.length() << " ";
|
|
parent->m_sub1->m_members.clear();
|
|
parent->m_sub1->m_area = 0;
|
|
parent->m_sub2->m_members.clear();
|
|
parent->m_sub2->m_area = 0;
|
|
for(h::list<ConcreteCell *>::iterator it = parent->m_members.begin(); !it; it++) {
|
|
if (target[(*it)->getID()].loc == 1 || target[(*it)->getID()].loc == -1) {
|
|
parent->m_sub1->m_members.push_back(*it);
|
|
parent->m_sub1->m_area += (*it)->getArea();
|
|
}
|
|
else {
|
|
parent->m_sub2->m_members.push_back(*it);
|
|
parent->m_sub2->m_area += (*it)->getArea();
|
|
}
|
|
}
|
|
cout << " after " << parent->m_sub1->m_members.length() << "/"
|
|
<< parent->m_sub2->m_members.length() << endl;
|
|
|
|
|
|
cout << "FIDM-21 : \tloc: " << initial_cut << " targetting: " << targets*100/parent->m_members.length() << "%" << endl;
|
|
cout << "FIDM-22 : \tstarting cuts= " << before_cuts << " final cuts= " << current_cuts << endl;
|
|
#endif
|
|
}
|
|
|
|
// ----- FM_updateGains()
|
|
// moves a cell between bins
|
|
#if 0
|
|
void FM_updateGains(ConcreteNet *net, int partition, int inc,
|
|
FM_cell target [], FM_cell *bin [],
|
|
int count_1 [], int count_2 []) {
|
|
|
|
for(ConcretePinList::iterator it = net->getPins().begin(); !it; it++) {
|
|
FM_cell *current = &(target[(*it)->getCell()->getID()]);
|
|
assert(current->cell != 0);
|
|
|
|
int old_gain = current->gain;
|
|
current->gain = 0;
|
|
|
|
// examine counts for the net on each pin
|
|
for(ConcretePinMap::iterator p_it = current->cell->getPins().begin(); !p_it; p_it++)
|
|
if ((*p_it)->isAttached()) {
|
|
int n_id = (*p_it)->getNet()->getID();
|
|
if (current->loc == 1 && count_1[n_id] == 1) current->gain++;
|
|
if (current->loc == 1 && count_2[n_id] == 0) current->gain--;
|
|
if (current->loc == 2 && count_1[n_id] == 0) current->gain--;
|
|
if (current->loc == 2 && count_2[n_id] == 1) current->gain++;
|
|
}
|
|
|
|
if (!current->locked) {
|
|
// remove cell from existing bin
|
|
int bin_num = min(max(0, old_gain),FM_MAX_BIN);
|
|
if (bin[bin_num] == current)
|
|
bin[bin_num] = current->next;
|
|
if (current->prev != 0)
|
|
current->prev->next = current->next;
|
|
if (current->next != 0)
|
|
current->next->prev = current->prev;
|
|
// add cell to correct bin
|
|
bin_num = min(max(0, current->gain),FM_MAX_BIN);
|
|
current->prev = 0;
|
|
current->next = bin[bin_num];
|
|
if (bin[bin_num] != 0)
|
|
bin[bin_num]->prev = current;
|
|
bin[bin_num] = current;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// partitionEqualArea()
|
|
//
|
|
/// \brief Splits a partition into two halves of equal area.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void partitionEqualArea(Partition *parent) {
|
|
float halfArea, area;
|
|
int i=0;
|
|
|
|
// which way to sort?
|
|
if (parent->m_vertical)
|
|
// sort by X position
|
|
qsort(parent->m_members, parent->m_numMembers, sizeof(ConcreteCell*), cellSortByX);
|
|
else
|
|
// sort by Y position
|
|
qsort(parent->m_members, parent->m_numMembers, sizeof(ConcreteCell*), cellSortByY);
|
|
|
|
// split the list
|
|
halfArea = parent->m_area*0.5;
|
|
parent->m_sub1->m_area = 0.0;
|
|
parent->m_sub1->m_numMembers = 0;
|
|
parent->m_sub1->m_members = (ConcreteCell**)realloc(parent->m_sub1->m_members,
|
|
sizeof(ConcreteCell*)*parent->m_numMembers);
|
|
parent->m_sub2->m_area = 0.0;
|
|
parent->m_sub2->m_numMembers = 0;
|
|
parent->m_sub2->m_members = (ConcreteCell**)realloc(parent->m_sub2->m_members,
|
|
sizeof(ConcreteCell*)*parent->m_numMembers);
|
|
|
|
for(; parent->m_sub1->m_area < halfArea; i++)
|
|
if (parent->m_members[i]) {
|
|
area = getCellArea(parent->m_members[i]);
|
|
parent->m_sub1->m_members[parent->m_sub1->m_numMembers++] = parent->m_members[i];
|
|
parent->m_sub1->m_area += area;
|
|
}
|
|
for(; i<parent->m_numMembers; i++)
|
|
if (parent->m_members[i]) {
|
|
area = getCellArea(parent->m_members[i]);
|
|
parent->m_sub2->m_members[parent->m_sub2->m_numMembers++] = parent->m_members[i];
|
|
parent->m_sub2->m_area += area;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// partitionScanlineMincut()
|
|
//
|
|
/// \brief Scans the cells within a partition from left to right and chooses the min-cut.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void partitionScanlineMincut(Partition *parent) {
|
|
#if 0
|
|
int current_cuts = 0;
|
|
int minimum_cuts = INT_MAX;
|
|
ConcreteCell *minimum_location = NULL;
|
|
double currentArea = 0, halfArea = parent->m_area * 0.5;
|
|
double areaFlexibility = parent->m_area * MAX_PARTITION_NONSYMMETRY;
|
|
double newLine, oldLine = -DBL_MAX;
|
|
|
|
for(ConcreteNetList::iterator n_it = m_design->nets.begin(); !n_it; n_it++)
|
|
(*n_it)->m_mark = 0;
|
|
for(h::list<ConcreteCell *>::iterator i = parent->m_members.begin();
|
|
!i.isDone(); i++) {
|
|
assert(*i);
|
|
for(ConcretePinMap::iterator j = (*i)->getPins().begin();
|
|
!j.isDone(); j++) {
|
|
assert(*j);
|
|
if((*j)->isAttached()) {
|
|
(*j)->getNet()->m_mark = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parent->vertical) {
|
|
parent->m_members.sort(sortByX);
|
|
int all1 = 0, all2 = 0;
|
|
h::list<ConcreteCell *>::iterator local = parent->m_members.begin();
|
|
for(; !local.isDone(); local++) {
|
|
currentArea += (*local)->getArea();
|
|
if (currentArea < halfArea-areaFlexibility)
|
|
continue;
|
|
if (currentArea > halfArea+areaFlexibility)
|
|
break;
|
|
newLine = (*local)->temp_x;
|
|
while(all1 < g_place_numNets && allNetsL2[all1]->getBoundingBox().left() <= newLine) {
|
|
if(allNetsL2[all1]->m_mark) {
|
|
current_cuts++;
|
|
}
|
|
all1++;
|
|
}
|
|
while(all2 < g_place_numNets && allNetsR2[all2]->getBoundingBox().right() <= newLine) {
|
|
if(allNetsR2[all2]->m_mark) {
|
|
current_cuts--;
|
|
}
|
|
all2++;
|
|
}
|
|
if (current_cuts < minimum_cuts) {
|
|
minimum_cuts = current_cuts;
|
|
minimum_location = *local;
|
|
}
|
|
oldLine = newLine;
|
|
}
|
|
}
|
|
else {
|
|
parent->m_members.sort(sortByY);
|
|
int all1 = 0, all2 = 0;
|
|
h::list<ConcreteCell *>::iterator local = parent->m_members.begin();
|
|
for(; !local.isDone(); local++) {
|
|
currentArea += (*local)->getArea();
|
|
if (currentArea < halfArea-areaFlexibility)
|
|
continue;
|
|
if (currentArea > halfArea+areaFlexibility)
|
|
break;
|
|
newLine = (*local)->temp_y;
|
|
while(all1 < g_place_numNets && allNetsB2[all1]->getBoundingBox().top() <= newLine) {
|
|
if(allNetsB2[all1]->m_mark) {
|
|
current_cuts++;
|
|
}
|
|
all1++;
|
|
}
|
|
while(all2 < g_place_numNets && allNetsT2[all2]->getBoundingBox().bottom() <= newLine) {
|
|
if(allNetsT2[all2]->m_mark) {
|
|
current_cuts--;
|
|
}
|
|
all2++;
|
|
}
|
|
if (current_cuts < minimum_cuts) {
|
|
minimum_cuts = current_cuts;
|
|
minimum_location = *local;
|
|
}
|
|
oldLine = newLine;
|
|
}
|
|
}
|
|
if (minimum_location == NULL) {
|
|
return partitionEqualArea(parent);
|
|
}
|
|
h::list<ConcreteCell *>::iterator it = parent->m_members.begin();
|
|
parent->m_sub1->m_members.clear();
|
|
parent->m_sub1->m_area = 0;
|
|
for(; *it != minimum_location; it++) {
|
|
parent->m_sub1->m_members.push_front(*it);
|
|
parent->m_sub1->m_area += (*it)->getArea();
|
|
}
|
|
parent->m_sub2->m_members.clear();
|
|
parent->m_sub2->m_area = 0;
|
|
for(; !it; it++) {
|
|
parent->m_sub2->m_members.push_front(*it);
|
|
parent->m_sub2->m_area += (*it)->getArea();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// reallocPartition()
|
|
//
|
|
/// \brief Reallocates a partition and all of its children.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void reallocPartition(Partition *p) {
|
|
|
|
if (p->m_leaf) {
|
|
return;
|
|
}
|
|
|
|
// --- INITIAL PARTITION
|
|
|
|
if (PARTITION_AREA_ONLY)
|
|
partitionEqualArea(p);
|
|
else
|
|
partitionScanlineMincut(p);
|
|
|
|
resizePartition(p);
|
|
|
|
// --- PARTITION IMPROVEMENT
|
|
if (p->m_level < REPARTITION_LEVEL_DEPTH) {
|
|
if (REPARTITION_HMETIS)
|
|
repartitionHMetis(p);
|
|
|
|
resizePartition(p);
|
|
}
|
|
|
|
reallocPartition(p->m_sub1);
|
|
reallocPartition(p->m_sub2);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// resizePartition()
|
|
//
|
|
/// \brief Recomputes the bounding boxes of the child partitions based on their relative areas.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void resizePartition(Partition *p) {
|
|
// compute the new bounding box
|
|
p->m_sub1->m_bounds.x = p->m_bounds.x;
|
|
p->m_sub1->m_bounds.y = p->m_bounds.y;
|
|
if (p->m_vertical) {
|
|
p->m_sub1->m_bounds.w = p->m_bounds.w*(p->m_sub1->m_area/p->m_area);
|
|
p->m_sub1->m_bounds.h = p->m_bounds.h;
|
|
p->m_sub2->m_bounds.x = p->m_bounds.x + p->m_sub1->m_bounds.w;
|
|
p->m_sub2->m_bounds.w = p->m_bounds.w*(p->m_sub2->m_area/p->m_area);
|
|
p->m_sub2->m_bounds.y = p->m_bounds.y;
|
|
p->m_sub2->m_bounds.h = p->m_bounds.h;
|
|
} else {
|
|
p->m_sub1->m_bounds.h = p->m_bounds.h*(p->m_sub1->m_area/p->m_area);
|
|
p->m_sub1->m_bounds.w = p->m_bounds.w;
|
|
p->m_sub2->m_bounds.y = p->m_bounds.y + p->m_sub1->m_bounds.h;
|
|
p->m_sub2->m_bounds.h = p->m_bounds.h*(p->m_sub2->m_area/p->m_area);
|
|
p->m_sub2->m_bounds.x = p->m_bounds.x;
|
|
p->m_sub2->m_bounds.w = p->m_bounds.w;
|
|
}
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// incrementalSubpartition()
|
|
//
|
|
/// \brief Adds new cells to an existing partition. Partition sizes/locations are unchanged.
|
|
///
|
|
/// The function recurses, adding new cells to appropriate subpartitions.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void incrementalSubpartition(Partition *p, ConcreteCell *newCells [], const int numNewCells) {
|
|
int c;
|
|
ConcreteCell **newCells1 = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*numNewCells),
|
|
**newCells2 = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*numNewCells);
|
|
int numNewCells1 = 0, numNewCells2 = 0;
|
|
float cut_loc;
|
|
|
|
assert(p);
|
|
|
|
// add new cells to partition list
|
|
p->m_members = (ConcreteCell**)realloc(p->m_members,
|
|
sizeof(ConcreteCell*)*(p->m_numMembers+numNewCells));
|
|
memcpy(&(p->m_members[p->m_numMembers]), newCells, sizeof(ConcreteCell*)*numNewCells);
|
|
p->m_numMembers += numNewCells;
|
|
|
|
// if is a leaf partition, finished
|
|
if (p->m_leaf) return;
|
|
|
|
// split new cells into sub-partitions based on location
|
|
if (p->m_vertical) {
|
|
cut_loc = p->m_sub2->m_bounds.x;
|
|
for(c=0; c<numNewCells; c++)
|
|
if (newCells[c]->m_x < cut_loc)
|
|
newCells1[numNewCells1++] = newCells[c];
|
|
else
|
|
newCells2[numNewCells2++] = newCells[c];
|
|
} else {
|
|
cut_loc = p->m_sub2->m_bounds.y;
|
|
for(c=0; c<numNewCells; c++)
|
|
if (newCells[c]->m_y < cut_loc)
|
|
newCells1[numNewCells1++] = newCells[c];
|
|
else
|
|
newCells2[numNewCells2++] = newCells[c];
|
|
}
|
|
|
|
if (numNewCells1 > 0) incrementalSubpartition(p->m_sub1, newCells1, numNewCells1);
|
|
if (numNewCells2 > 0) incrementalSubpartition(p->m_sub2, newCells2, numNewCells2);
|
|
|
|
free(newCells1);
|
|
free(newCells2);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// incrementalPartition()
|
|
//
|
|
/// \brief Adds new cells to an existing partition. Partition sizes/locations are unchanged.
|
|
///
|
|
/// The function recurses, adding new cells to appropriate subpartitions.
|
|
//
|
|
// --------------------------------------------------------------------
|
|
void incrementalPartition() {
|
|
int c = 0, c2 = 0;
|
|
int numNewCells = 0;
|
|
ConcreteCell **allCells = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*g_place_numCells),
|
|
**newCells = (ConcreteCell **)malloc(sizeof(ConcreteCell*)*g_place_numCells);
|
|
|
|
assert(g_place_rootPartition);
|
|
|
|
// update cell list of root partition
|
|
memcpy(allCells, g_place_concreteCells, sizeof(ConcreteCell*)*g_place_numCells);
|
|
qsort(allCells, g_place_numCells, sizeof(ConcreteCell*), cellSortByID);
|
|
qsort(g_place_rootPartition->m_members, g_place_rootPartition->m_numMembers,
|
|
sizeof(ConcreteCell*), cellSortByID);
|
|
|
|
// scan sorted lists and collect cells not in partitions
|
|
while(!allCells[c++]);
|
|
while(!g_place_rootPartition->m_members[c2++]);
|
|
|
|
for(; c<g_place_numCells; c++, c2++) {
|
|
while(c2 < g_place_rootPartition->m_numMembers &&
|
|
allCells[c]->m_id > g_place_rootPartition->m_members[c2]->m_id) c2++;
|
|
while(c < g_place_numCells &&
|
|
(c2 >= g_place_rootPartition->m_numMembers ||
|
|
allCells[c]->m_id < g_place_rootPartition->m_members[c2]->m_id)) {
|
|
// a new cell!
|
|
newCells[numNewCells++] = allCells[c];
|
|
c++;
|
|
}
|
|
}
|
|
|
|
printf("QPRT-50 : \tincremental partitioning with %d new cells\n", numNewCells);
|
|
if (numNewCells>0) incrementalSubpartition(g_place_rootPartition, newCells, numNewCells);
|
|
|
|
free(allCells);
|
|
free(newCells);
|
|
}
|
|
ABC_NAMESPACE_IMPL_END
|
|
|