/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Yana.java
* Written by: Andreas Uebelhoer, Alexander Bieles, Emre Selegin (Team 6)
*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.routing.experimentalLeeMoore1;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.RoutingArray;
import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.Tupel;
import com.sun.electric.tool.util.concurrent.utils.ElapseTimer;
public class yana extends BenchmarkRouter {
protected final boolean output = enableOutput.getBooleanValue();
/*
* GUI
*/
private static int progressMax = 0;
private static int progress = 0;
private static UserInterface gui;
/*
* Parameters
*/
// public RoutingParameter maxThreadsParameter = new
// RoutingParameter("threads", "Number of Threads to use:", 4);
public static int maxThreads;
public RoutingParameter numPartitionsParameter = new RoutingParameter("partitions", "Number of partitions to use:",
26); // Factory value must be constant
// Math.max(26, Math.max(Runtime.getRuntime().availableProcessors(), numThreads.getIntValue())));
// public RoutingParameter numPartitionsParameter = new
// RoutingParameter("partitions", "Number of partitions to use:", 5);
public static int numPartitions;
public RoutingParameter regionDivideMethodParameter = new RoutingParameter("region-generation-method",
"Method used to devide the grid into regions:", 1);
public static int regionDivideMethod;
// 1=optimal balanced in x and y direction
// 2=simple stripes
// 3=adapted so that regions have the same ratio than the grid dimensions
public RoutingParameter maxLayerUseParameter = new RoutingParameter("maxLayerUse",
"Restrict number of layers to use", 5);
public static int maxLayerUse;
public RoutingParameter minimumRegionBorderLengthParameter = new RoutingParameter("minimumRegionBorderLength",
"Minumum length the regions must have:", 20);
public static int minimumRegionBorderLength;
// public RoutingParameter widthWhereJustOneWireIsPermittedParameter = new
// RoutingParameter("widthWhereJustOneWireIsPermitted",
// "Wire-thickness + 2*spacing-length to next wire", 9);
public static int distanceBetweenWires; // should be = wirethickness +
// 2*requiredspacing
// if there are to much regions, so that this constraint cant be held, than
// the numpartitions will be reduced until this constraint is fulfilled
/*
* Others
*/
public static CyclicBarrier barrierRouting;
public static CyclicBarrier barrierWiring;
public static ConcurrentHashMap<Integer, Boolean> unroutedNets = new ConcurrentHashMap<Integer, Boolean>();
/**
* Method to return the name of this routing algorithm.
*
* @return the name of this routing algorithm.
*/
@Override
public String getAlgorithmName() {
return "Lee/Moore - 1";
}
/**
* Method to do Simple routing.
*/
@Override
protected void runRouting(Cell cell, List<RoutingSegment> segmentsToRoute, List<RoutingLayer> allLayers,
List<RoutingContact> allContacts, List<RoutingGeometry> blockages) {
// printChipStatistics(cell, segmentsToRoute, allLayers, allContacts,
// blockages);
ElapseTimer timer = ElapseTimer.createInstance().start();
if (output)
System.out.println("electric goes yana...");
int maxRuntimeMs = this.maxRuntime.getIntValue() * 1000;
maxThreads = (numThreads.getIntValue() < 1) ? 1 : numThreads.getIntValue();
numPartitions = (numPartitionsParameter.getIntValue() < 1) ? 1 : numPartitionsParameter.getIntValue();
minimumRegionBorderLength = (minimumRegionBorderLengthParameter.getIntValue() < 2) ? 2
: minimumRegionBorderLengthParameter.getIntValue();
// distanceBetweenWires =
// (widthWhereJustOneWireIsPermittedParameter.getIntValue() < 1) ? 1 :
// widthWhereJustOneWireIsPermittedParameter.getIntValue();
regionDivideMethod = regionDivideMethodParameter.getIntValue();
// regionDivideMethod can be any value, but if it is an unkown one,
// there will be just one region
maxLayerUse = maxLayerUseParameter.getIntValue();
if (maxLayerUse <= 0 || maxLayerUse > countLayers(allLayers)) {
maxLayerUse = countLayers(allLayers);
}
int dist = 0;
int width = 0;
int currentLayer = 0;
for (RoutingLayer rl : allLayers) {
if (rl.isMetal() && currentLayer < maxLayerUse) {
if (rl.getMinSpacing(rl) > dist) {
dist = (int) Math.round(rl.getMinSpacing(rl));
}
if (rl.getMinWidth() > width) {
width = (int) Math.round(rl.getMinWidth());
}
currentLayer++;
}
}
// distance: free space needed between two objects on the same layer
// width: width of a wire
// assumption: vias are width+1 thick (except vias from the last layer
if (width < 5) {
width++;
}
distanceBetweenWires = dist + width;
if (output)
System.out.println("Running " + maxThreads + " Threads on " + numPartitions + " partitions each minimum "
+ minimumRegionBorderLength + " length and " + distanceBetweenWires + " wire spacing.");
initProgress();
initializeWiringClass(allLayers, allContacts);
// for testing purposes: identify blocking cells -> will be deleted
// later
// Iterator<NodeInst> iter = cell.getNodes();
// while (iter.hasNext()) {
// NodeInst node = iter.next();
// if (node.getName().contains("blockage")) {
// for (RoutingLayer rl : allLayers) {
// RoutingGeometry blockage = new RoutingGeometry(rl, node.getBounds(),
// 0);
// blockages.add(blockage);
// }
// }
// }
// create barriers
barrierRouting = new CyclicBarrier(maxThreads, new Runnable() {
public void run() {
WorkPool.prepare();
}
});
barrierWiring = new CyclicBarrier(maxThreads);
// configure the Tupel-class static variables
Tupel.setOffset(cell.getBounds().getLambdaX(), cell.getBounds().getLambdaY(), 10, output);
// the global routing array, where the routing will be done from each
// thread
RoutingArray ra = new RoutingArray(cell, maxLayerUse, blockages, 3);
// DEBUG
// System.out.println("Interessantes Tupel: " +
// Tupel.convertElectricToRoutingArrayCoordinate_X(208) + "," +
// Tupel.convertElectricToRoutingArrayCoordinate_Y(101));
// set start and end points as blocked
markStartEndAsBlocked(segmentsToRoute, ra);
// create all workers
WorkerThread[] workerObjects = new WorkerThread[maxThreads];
Thread[] workerThreads = new Thread[maxThreads];
for (int i = 0; i < maxThreads; i++) {
workerObjects[i] = new WorkerThread(i);
workerThreads[i] = new Thread(workerObjects[i]);
// do not start the threads here, because they have to be
// initialized first
}
maxRuntimeMs = (int) (timer.currentTimeLong()) + maxRuntimeMs; // calculate
// runtime
// without
// initialization
WorkerThread.init(workerObjects, maxLayerUse, ra, segmentsToRoute, maxRuntimeMs, output);
// start all threads
for (int i = 0; i < maxThreads; i++) {
workerThreads[i].start();
}
// wait until threads have finished their work. afterwards we can do the
// return
try {
for (int i = 0; i < maxThreads; i++) {
workerThreads[i].join();
}
} catch (InterruptedException ex) {
Logger.getLogger(yana.class.getName()).log(Level.SEVERE, null, ex);
}
if (output)
System.out.println("yana complete...");
closeProgress();
if (output) {
timer.end();
System.out.println("YANA-time: " + timer);
}
System.gc();
}
private void initializeWiringClass(List<RoutingLayer> allLayers, List<RoutingContact> allContacts) {
// map metal layers which can be used for routing
int metalLayers = 0;
HashMap<String, Integer> metalLayerMap = new HashMap<String, Integer>();
for (RoutingLayer rl : allLayers) {
if (rl.isMetal()) {
metalLayerMap.put(rl.getName(), metalLayers);
metalLayers++;
}
}
Wiring.init(allLayers, metalLayerMap, allContacts, output);
}
private int countLayers(List<RoutingLayer> allLayers) {
int layer = 0;
for (RoutingLayer l : allLayers) {
if (l != null && l.isMetal()) {
layer++;
}
}
return layer;
}
/**
* print some statistics about the chip
*
*
* @param cell
* @param segmentsToRoute
* @param allLayers
* @param allContacts
* @param blockages
*/
public void printChipStatistics(Cell cell, List<RoutingSegment> segmentsToRoute, List<RoutingLayer> allLayers,
List<RoutingContact> allContacts, List<RoutingGeometry> blockages) {
int metalLayers = 0;
for (RoutingLayer rl : allLayers) {
if (rl.isMetal()) {
metalLayers++;
}
}
int[] layerDistance = new int[metalLayers];
int[] layerMembership = new int[metalLayers];
int[][] crossLayerMembership = new int[metalLayers][metalLayers];
int singleLayer = 0;
int crossLayer = 0;
int maxNetID = Integer.MIN_VALUE;
for (RoutingSegment rs : segmentsToRoute) {
maxNetID = Math.max(maxNetID, rs.getNetID());
int minStart = Integer.MAX_VALUE;
int maxStart = Integer.MIN_VALUE;
for (RoutingLayer rl : rs.getStartLayers()) {
minStart = Math.min(minStart, rl.getMetalNumber());
maxStart = Math.max(maxStart, rl.getMetalNumber());
}
int minFinish = Integer.MAX_VALUE;
int maxFinish = Integer.MIN_VALUE;
for (RoutingLayer rl : rs.getFinishLayers()) {
minFinish = Math.min(minFinish, rl.getMetalNumber());
maxFinish = Math.max(maxFinish, rl.getMetalNumber());
}
if (minStart == maxStart && minFinish == maxFinish) {
int distance = Math.abs(minStart - minFinish);
layerDistance[distance]++;
if (minStart == minFinish) {
singleLayer++;
layerMembership[minStart - 1]++;
} else {
int min = Math.min(minStart, minFinish);
int max = Math.max(minStart, minFinish);
crossLayerMembership[min - 1][max - 1]++;
crossLayer++;
}
}
}
int[] nets = new int[maxNetID + 1];
for (RoutingSegment rs : segmentsToRoute) {
nets[rs.getNetID()]++;
}
int numberOfNets = 0;
int maxSegments = Integer.MIN_VALUE;
for (int i = 0; i < nets.length; i++) {
if (nets[i] != 0) {
numberOfNets++;
}
maxSegments = Math.max(maxSegments, nets[i]);
}
int[] numberOfSegments = new int[maxSegments];
for (int i = 0; i < nets.length; i++) {
if (nets[i] != 0) {
numberOfSegments[nets[i] - 1]++;
}
}
int[] blockagesOnLayer = new int[metalLayers];
for (RoutingGeometry rg : blockages) {
blockagesOnLayer[rg.getLayer().getMetalNumber() - 1]++;
}
System.out.println("################### Cell statistics ########################");
System.out.println();
System.out.println();
System.out.print("#Metal-Layers: " + metalLayers + " { ");
for (RoutingLayer rl : allLayers) {
if (rl.isMetal()) {
System.out.print(rl.getMetalNumber() + ", ");
}
}
System.out.println("}\n");
System.out.println("#Segments: " + segmentsToRoute.size());
System.out.println("\t on one layer: " + singleLayer);
for (int i = 0; i < layerMembership.length; i++) {
if (layerMembership[i] != 0) {
System.out.println("\t\t Metal-" + (i + 1) + ": " + layerMembership[i]);
}
}
System.out.println("\t on two layers: " + crossLayer);
for (int i = 0; i < crossLayerMembership.length; i++) {
for (int j = 0; j < crossLayerMembership[0].length; j++) {
if (crossLayerMembership[i][j] != 0) {
System.out.println("\t\t Metal-" + (i + 1) + " - Metal-" + (j + 1) + ": "
+ crossLayerMembership[i][j]);
}
}
}
System.out.println();
System.out.println("layer distance distribution");
for (int i = 0; i < layerDistance.length; i++) {
if (layerDistance[i] != 0) {
System.out.println("\t distance " + i + ": " + layerDistance[i]);
}
}
System.out.println();
System.out.println("#Blockages: " + blockages.size());
for (int i = 0; i < blockagesOnLayer.length; i++) {
if (blockagesOnLayer[i] != 0) {
System.out.println("\t on Metal-" + (i + 1) + ": " + blockagesOnLayer[i]);
}
}
System.out.println();
int countNumSegments = 0;
System.out.println("#Nets: " + numberOfNets);
for (int i = 0; i < numberOfSegments.length; i++) {
if (numberOfSegments[i] != 0) {
countNumSegments += numberOfSegments[i] * (i + 1);
System.out.print("\t " + (i + 1) + " segments: " + numberOfSegments[i] + "{ ");
for (int j = 0; j < nets.length; j++) {
if (nets[j] == (i + 1)) {
System.out.print(j + ", ");
}
}
System.out.println("}");
}
}
System.out.println("\tsum: " + countNumSegments + " segments");
System.out.println("############################################################");
System.out.println();
}
/**
* Initializes progress bar
*/
public static void initProgress() {
gui = Job.getUserInterface();
gui.startProgressDialog("Yana is working for you", null);
gui.setProgressNote("Running...");
gui.setProgressValue(0);
}
/**
* Increases maximum value used in progress bar
*
* @param size
* value to add to current maximum value
*/
synchronized public static void setProgressMax(int size) {
progressMax += size;
}
/**
* Update progress bar. Marks one job as done
*/
synchronized public static void updateProgress() {
progress++;
// System.out.println("Progress: "+(double)progress/progressMax*100);
gui.setProgressNote("Routing segment " + progress + "/" + progressMax);
gui.setProgressValue((int) ((double) progress / progressMax * 100));
}
/**
* Hides progess bar
*/
public static void closeProgress() {
gui.stopProgressDialog();
}
/**
* Mark start and end points of a routing segment as blocked
*
* @param segmentsToRoute
* Routing Segments
* @param ra
* Routing Array
*/
private void markStartEndAsBlocked(List<RoutingSegment> segmentsToRoute, RoutingArray ra) {
Tupel[] startEndPoints = new Tupel[18];
int i;
for (RoutingSegment rs : segmentsToRoute) {
// original points
i = 0;
Tupel start = new Tupel(rs.getStartEnd().getLocation(), rs.getStartLayers().get(0).getMetalNumber() - 1);
Tupel end = new Tupel(rs.getFinishEnd().getLocation(), rs.getFinishLayers().get(0).getMetalNumber() - 1);
// DEBUG
// if(start.getX_InsideRoutingArray()==93 &&
// start.getY_InsideRoutingArray()==50){
// System.out.println("GOT IT");
// }
// if(end.getX_InsideRoutingArray()==93 &&
// end.getY_InsideRoutingArray()==50){
// System.out.println("GOT IT");
// }
startEndPoints[i++] = start;
startEndPoints[i++] = end;
// points right and top of the original points
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() + 1, start.getY_InsideRoutingArray(), start
.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray(), start.getY_InsideRoutingArray() + 1, start
.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() + 1, start.getY_InsideRoutingArray() + 1,
start.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() - 1, start.getY_InsideRoutingArray(), start
.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray(), start.getY_InsideRoutingArray() - 1, start
.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() - 1, start.getY_InsideRoutingArray() - 1,
start.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() + 1, start.getY_InsideRoutingArray() - 1,
start.getLayer(), false);
startEndPoints[i++] = new Tupel(start.getX_InsideRoutingArray() - 1, start.getY_InsideRoutingArray() + 1,
start.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() + 1, end.getY_InsideRoutingArray(), end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray(), end.getY_InsideRoutingArray() + 1, end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() + 1, end.getY_InsideRoutingArray() + 1, end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() - 1, end.getY_InsideRoutingArray(), end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray(), end.getY_InsideRoutingArray() - 1, end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() - 1, end.getY_InsideRoutingArray() - 1, end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() + 1, end.getY_InsideRoutingArray() - 1, end
.getLayer(), false);
startEndPoints[i++] = new Tupel(end.getX_InsideRoutingArray() - 1, end.getY_InsideRoutingArray() + 1, end
.getLayer(), false);
ra.reserveForRouting(startEndPoints, rs.getNetID());
}
ra.markReserved();
}
public yana() {
super();
}
public static void markSegmentAsUnroutable(RoutingSegment rs) {
unroutedNets.put(rs.hashCode(), false);
}
public static boolean isRouteable(RoutingSegment rs) {
if (unroutedNets.get(rs.hashCode()) == null) {
// segment can be routed
return true;
} else {
return false;
}
}
}