ioPlacer finds an near-optimal placement for IO pins through the use of a Hungarian Matching Algorithm.
If you want to use this as part of the OpenROAD project you should build it and use it from inside the integrated openroad app. The standalone version is available as legacy code.
git clone --recursive https://github.com/The-OpenROAD-Project/ioPlacer.git
cd ioPlacer/
make PARALLEL=nthreads
NOTE: use PARALLEL=nthreads
instead of -j nthreads
The binary file will be on ioPlacer's base folder.
cd ioPlacer/
make lib
The library file (libioPlacer.a) will be on the repository root folder
An edge represents a core boundary. Below there is a visual representation of how the algorithm understands the boundaries.
/********************************************
* <---- *
* *
* 3st edge upperBound *
* *------------------x *
* | | *
* | | | ^ *
* | 4th | | 2nd | *
* | edge | | edge | *
* V | | | *
* | | *
* x------------------* *
* lowerBound 1st edge *
* ----> *
*******************************************/
A slot is a valid position for a IO pin. This position usually is in the core boundary where a track of the given metal layer is present. The slots are created following the edges (1, 2, 3, and then 4 as show above).
A section is a set of sequential slots. Each section is processed independently by the Hungarian matching algorithm. When if using the random placement, the number and capacity of sections as well as related arguments (e.g., pin spread, increase factor) are not considered.
To properly run IO Placement there are a few mandatory arguments that must be defined.
There are optional flags that can be used.
Your command line to run ioPlacer should look like this.
./ioPlacer -l input.lef -d input.def -o output.def -h 5 -v 6
You can also check the arguments and a brief description by running the following command.
./ioPlacer
0
do NOT use random, i.e., normal Hungarian Algorithm.
1
shuffle all slots creating a stack, pop top item and assign to first IO pin
2
shuffle all IO pins, walk edges (see above) placing pins in equal distances
3
shuffle all IO pins; divide in 4 groups; assign each group to a edge; start placing on sequential slots from the middle of the edge.
If a design has 100 pins, each section has 10 slots (-n 10
) and only 50% can be used (-m 0.5
), then only 5 pins can be placed in each section.
If ioPlacer tries to assign a pin to a section with 5 IO pins, instead of increasing the size using -s
or the usage with -x
it will assign the IO pin to the next section.
In the case where there are no other section available, then the program falls back to using the -s and -x
values to change the capacity and usage for the next iteration.
You can run ioPlacer with RePlAce, using the following script:
bash ./RePlAce-pin/scripts/replace_ioplace_loop.sh <ioPlacerBin> <ioplacerArgs> <RePlAceBin> <replaceArgs> <iterations> <lefFile> <defFile> <output> <defName> <hasIoPlace>
Each parameter of the script is described below:
This script implement a loop with RePlAce and ioPlacer, as shown bellow:
An example with a benchmark from ISPD18 contest is shown below:
bash ./scripts/replace_ioplace_loop.sh ioPlacer/build/ioPlacer '-h 3 -v 4' RePlAce/build/replace '-den 0.8 -plot' 5 ispd18_test2/ispd18_test2.input.lef ispd18_test2/ispd18_test2.input.def output ispd18_test2.input 1
Before running ioPlacer the data structures should be initialized.
void initCore(point lowerBounds, point upperBounds, DBU minSpacingX,
DBU minSpacingY, DBU initTrackX, DBU initTrackY,
DBU minAreaX, DBU minAreaY, DBU minWidthX, DBU minWidthY);
The function initCore initiliazes the circuit core. Six parameters should be passed to this function:
void setMetalLayers(int horizontalMetalLayer, int verticalMetalLayer);
The function setMetalLayers defines on which layers the pins should be placed.
void addIOPin(std::string name, std::string netName, box bounds,
std::string direction);
The function addIOPin adds an IOPin to the data structure. All IO Pins should be individually added through this function.
void addInstPin(std::string net, std::string pinName, point pos);
The function addInstPin adds a pin of an instance to the data structure. All pins should be individually added through this function.
A few parameters in ioPlacer are optional, they are set to a default value but can be changed if needed.
void setSlotsPerSection(unsigned slotsPerSection, float increaseFactor);
The function setSlotsPerSection sets the number of slots per section and the increase factor. If the algorithm can not assign each pin to a section, the number of slots per section is increased by this factor, e.g., 0.1f = 10% increase.
void setSlotsUsagePerSection(float usagePerSection, float increaseFactor);
The function setSlotsUsagePerSection sets the maximum slot usage per section.
void forcePinSpread(bool force);
The function forcePinSpread defines if ioPlacer should try to force the spread of IO Pins if the algorithm can not assign each pin to a section or if it should immediately increase the section's usage.
std::vector<Pin_t> run(bool returnHPWL = false);
After everything is properly set, the run function should be called. If a true argument is passed, this function prints the IO Pins HPWL. This function returns a vector with Pin_t structs. This struct is defined in IOPlacement.h, it contains the name of the IO pin, its new position and its orientation (e.g., 'N', 'S', 'W' or 'E').