OpenFPGA/abc/src/phys/place/place_partition.c

1141 lines
37 KiB
C
Raw Normal View History

/*===================================================================*/
//
// 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