/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: EndPointMarker.java
* Written by: Christian Julg, Jonas Thedering (Team 1)
*
* 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.experimentalAStar1;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.sun.electric.tool.routing.RoutingFrame.RoutingLayer;
/**
* Determines the possible start/finish layers for the paths in the nets
* and adds corresponding markings to the map
*
* @author Christian Jülg
* @author Jonas Thedering
*/
public class EndPointMarker {
private boolean DEBUG = false;
private static final int CLEAR = 0;
private static final int CORE_BLOCKED = -1;
private static final int CORE_FREE_SURROUNDING_BLOCKED = -2;
private static Random random = new Random(8682522807148012L);
Map map;
public EndPointMarker(Map map) {
this.map = map;
DEBUG &= AStarRoutingFrame.getInstance().isOutputEnabled();
}
/**
* marks start and finish locations for each segment,
* to prevent other Nets that are routed earlier to run over these endpoints
*/
public void markStartAndFinish(List<Net> netList) {
long start = 0;
if (DEBUG) {
start = System.currentTimeMillis();
}
ArrayList<EndPoint> endPoints = new ArrayList<EndPoint>();
for (Net net : netList) {
net.initialize(); // needed before Goal()
List<Path> paths = net.getPaths();
for (int pathIndex=0; pathIndex<paths.size(); pathIndex++) {
Path path = paths.get(pathIndex);
EndPoint startPoint = new EndPoint(path, net, EndPoint.START);
List<RoutingLayer> layers = path.segment.getStartLayers();
startPoint.possibleLayers = new int[layers.size()];
startPoint.fullyMarkedLayers = new int[layers.size()];
// assert startPoint.possibleLayers.length <= map.getLayers() : "Error: There are not enough valid layers configured, or this segment has too many startLayers set";
for (int layerIndex=0; layerIndex<layers.size(); layerIndex++) {
RoutingLayer rl = layers.get(layerIndex);
int z = rl.getMetalNumber() - 1;
startPoint.possibleLayers[layerIndex] = z;
}
endPoints.add(startPoint);
EndPoint finishPoint = new EndPoint(path, net, EndPoint.FINISH);
layers = path.segment.getFinishLayers();
finishPoint.possibleLayers = new int[layers.size()];
finishPoint.fullyMarkedLayers = new int[layers.size()];
for (int layerIndex=0; layerIndex<layers.size(); layerIndex++) {
RoutingLayer rl = layers.get(layerIndex);
int z = rl.getMetalNumber() - 1;
finishPoint.possibleLayers[layerIndex] = z;
}
endPoints.add(finishPoint);
findPreferredLayer(startPoint, finishPoint);
}
}
// try to mark all layers for each endPoint, with surrounding
boolean repeat = true;
while(repeat) {
repeat = false;
for (EndPoint endPoint : endPoints) {
int netID = endPoint.net.getNetID();
// mark one layer for this endpoint so endpoints take turns in choosing layers
while(endPoint.markingIndex < endPoint.possibleLayers.length) {
int z = endPoint.possibleLayers[endPoint.markingIndex];
++endPoint.markingIndex;
int status = isEndpointFree(endPoint, z, netID, true);
if (status == CLEAR) {
setEndpoint(endPoint, z, netID);
endPoint.fullyMarkedLayers[endPoint.fullyMarkedCount] = z;
endPoint.fullyMarkedCount++;
break;
}
// ignore else
}
if(endPoint.markingIndex < endPoint.possibleLayers.length)
repeat = true;
}
}
for (EndPoint endPoint : endPoints) {
int netID = endPoint.net.getNetID();
// mark one layer for this endpoint so endpoints take turns in choosing layers
for(int i=0; i < endPoint.possibleLayers.length; i++) {
int z = endPoint.possibleLayers[i];
int status = map.getStatus(endPoint.getX(), endPoint.getY(), z);
if (status == Map.CLEAR) {
assert isEndpointFree(endPoint, z, netID, true) == CORE_FREE_SURROUNDING_BLOCKED : isEndpointFree(endPoint, z, netID, true);
map.setStatus(endPoint.getX(), endPoint.getY(), z, netID);
}
}
}
for(EndPoint endPoint : endPoints) {
// We must not have an empty layer list
if(endPoint.fullyMarkedCount == 0) {
endPoint.path.pathUnroutable = true;
++endPoint.fullyMarkedCount;
endPoint.fullyMarkedLayers[0] = endPoint.possibleLayers[0];
}
endPoint.setZ();
}
if (DEBUG) {
System.out.printf("Master: markStartAndFinish() took %d ms for %d nets\n", System.currentTimeMillis() - start, netList.size());
}
}
/** Determines how many blocking markings are at the 4 mark points for the given endPoint and layer
*
* @returns CLEAR, CORE_BLOCKED or CORE_FREE_SURROUNDING_BLOCKED
*/
private int isEndpointFree(EndPoint endPoint, int z, int netID, boolean checkSurrounding) {
int x = endPoint.getX();
int y = endPoint.getY();
int xDiff = endPoint.isRight() ? 1 : -1;
int yDiff = endPoint.isAbove() ? 1 : -1;
int[] xArgs = new int[4];
int[] yArgs = new int[4];
xArgs[0] = x;
yArgs[0] = y;
xArgs[1] = x + xDiff;
yArgs[1] = y;
xArgs[2] = x;
yArgs[2] = y + yDiff;
xArgs[3] = x + xDiff;
yArgs[3] = y + yDiff;
int status = map.getStatus(xArgs[0], yArgs[0], z);
// // TODO: check for != Map.X would mean Endpoints can be in same grid point as blockages,
// // could lead to DRC errors!
// if (status != Map.CLEAR && status != netID && status != Map.X) {
// return CORE_BLOCKED;
// }
if (status != Map.CLEAR && status != netID) {
return CORE_BLOCKED;
}
if (checkSurrounding) {
for (int i = 1; i < 4; i++) {
status = map.getStatus(xArgs[i], yArgs[i], z);
// // TODO: check for != Map.X would mean Endpoints can be in same grid point as blockages,
// // could lead to DRC errors!
// if (status != Map.CLEAR && status != netID && status != Map.X) {
// return CORE_FREE_SURROUNDING_BLOCKED;
// }
if (status != Map.CLEAR && status != netID) {
return CORE_FREE_SURROUNDING_BLOCKED;
}
}
}
return CLEAR;
}
/** Adds the 4 markings for the given endPoint and layer */
private void setEndpoint(EndPoint endPoint, int z, int netID) {
int x = endPoint.getX();
int y = endPoint.getY();
int xDiff = endPoint.isRight() ? 1 : -1;
int yDiff = endPoint.isAbove() ? 1 : -1;
int[] xArgs = new int[4];
int[] yArgs = new int[4];
xArgs[0] = x;
yArgs[0] = y;
xArgs[1] = x + xDiff;
yArgs[1] = y;
xArgs[2] = x;
yArgs[2] = y + yDiff;
xArgs[3] = x + xDiff;
yArgs[3] = y + yDiff;
map.setStatus(xArgs[0], yArgs[0], z, netID);
map.setStatus(xArgs[1], yArgs[1], z, netID);
map.setStatus(xArgs[2], yArgs[2], z, netID);
map.setStatus(xArgs[3], yArgs[3], z, netID);
if(DEBUG)
for(int i=0; i<4; ++i)
System.out.printf("EndPointMarker: Marking (%.2f, %.2f)(%d,%d) as #%d for net %d\n", xArgs[i]*map.getScalingFactor()-map.getDispX()+map.getScalingFactor()/2f, yArgs[i]*map.getScalingFactor()-map.getDispY()+map.getScalingFactor()/2f, xArgs[i], yArgs[i], i, endPoint.net.getElectricNetID());
}
/**
* Selects one layer for the endpoints of the given segment that should be used preferably
*
* If both endpoints have common layers, one of these is chosen.
*/
public void findPreferredLayer(EndPoint startPoint, EndPoint finishPoint) {
// there can be multiple start/finish layers
int[] startLayerNums = startPoint.possibleLayers;
int[] finishLayerNums = finishPoint.possibleLayers;
int minS = startLayerNums[0];
int maxS = startLayerNums[startLayerNums.length - 1];
int minF = finishLayerNums[0];
int maxF = finishLayerNums[finishLayerNums.length - 1];
Arrays.sort(startLayerNums);
Arrays.sort(finishLayerNums);
int[] common = new int[startLayerNums.length];
int commonCount = 0;
int iFinish = 0;
for (int iStart = 0; iStart < startLayerNums.length; iStart++) {
if (iFinish == finishLayerNums.length) {
break;
} else if (startLayerNums[iStart] == finishLayerNums[iFinish]) {
common[commonCount++] = startLayerNums[iStart];
}
iFinish++;
}
if (DEBUG) {
System.out.printf("EndPointMarker.initStartFinishZ: minS:%d, maxS:%d, minF:%d, maxF:%d\n", minS, maxS, minF, maxF);
System.out.printf("there are %d common layers: %s\n", commonCount, Arrays.toString(common));
}
// important: only the first commonCount elements of common[] are valid!
if (commonCount > 0) {
int idx = random.nextInt(commonCount);
startPoint.preferLayer(common[idx]);
finishPoint.preferLayer(common[idx]);
}
}
}