/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: AStarMaster.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.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.tool.routing.RoutingFrame.RoutePoint; import com.sun.electric.tool.routing.RoutingFrame.RouteWire; import com.sun.electric.tool.routing.RoutingFrame.RoutingContact; import com.sun.electric.tool.routing.RoutingFrame.RoutingGeometry; import com.sun.electric.tool.routing.RoutingFrame.RoutingLayer; import com.sun.electric.tool.routing.RoutingFrame.RoutingSegment; /** * Creates the jobs for the worker threads and processes the results * * @author Jonas Thedering * @author Christian Jülg */ public class AStarMaster { private boolean DEBUG = false; // Displacement to map the given coordinates to the field array private final int dispX; private final int dispY; private ExecutorCompletionService<Net> netCompletionService; private List<Net> netList; private List<Net> unroutedNetList; private List<Net> activeNetList = new LinkedList<Net>(); private List<ObjectPool<Node>> nodePools; private List<ObjectPool<Storage>> storagePools; private RoutingLayer[] metalLayers; private RoutingContact[] metalPins; private List<RoutingContact> allContacts; private final Map map; private int poolSize; private int totalNumPaths; private int threadCount; private long shutdownTime; private int unroutableNetCount = 0; private int unroutablePathCount = 0; public AStarMaster(ExecutorService service, Map map, List<ObjectPool<Node>> nodePools, List<ObjectPool<Storage>> storagePools, RoutingLayer[] metalLayers, RoutingContact[] metalPins, int threadCount, long shutDownTime) { netCompletionService = new ExecutorCompletionService<Net>(service); this.nodePools = nodePools; this.storagePools = storagePools; this.map = map; this.metalLayers = metalLayers; this.metalPins = metalPins; this.threadCount = threadCount; this.dispX = map.getDispX(); this.dispY = map.getDispY(); this.poolSize = nodePools.size(); this.shutdownTime = shutDownTime; DEBUG &= AStarRoutingFrame.getInstance().isOutputEnabled(); } private void run() { long startTime = 0; long masterTimeActiveStart = 0; long masterTimeWaitingStart = 0; long masterTimeActiveSum = 0; long masterTimeWaitingSum = 0; if (DEBUG) { long currentTime = System.currentTimeMillis(); masterTimeActiveStart = currentTime; startTime = currentTime; } int invalidLength = 0; int invalidPathSum = 0; int completedNetCount = 0; int completedPathCount = 0; int invalidNetSum = 0; EndPointMarker marker = new EndPointMarker(map); marker.markStartAndFinish(netList); processUnroutables(); // Schedule one net per thread at the start for (int i = 0; i < threadCount; ++i) { scheduleUnroutedNet(); } boolean shutdown = false; // The "main loop", which waits for finishing workers and creates new jobs while (completedNetCount < netList.size() && !(activeNetList.isEmpty() && shutdown)) { try { if (DEBUG) { long currentTime = System.currentTimeMillis(); masterTimeActiveSum += currentTime - masterTimeActiveStart; masterTimeWaitingStart = currentTime; } Future<Net> future = netCompletionService.take(); Net net = future.get(); if (DEBUG) { long currentTime = System.currentTimeMillis(); masterTimeWaitingSum += currentTime - masterTimeWaitingStart; masterTimeActiveStart = currentTime; } // if there are fewer Nets than threads left, // remove a nodepool to free up memory while (netList.size() - completedNetCount < poolSize) { synchronized (nodePools) { if(DEBUG) System.out.println("Master: removed a nodepool!"); nodePools.remove(0); storagePools.remove(0); poolSize--; } } List<Path> paths = net.getPaths(); boolean invalidFound = false; boolean[] pathInvalid = new boolean[paths.size()]; boolean unroutablePathFound = false; // Check all paths routed for validity for (int pathIdx = 0; pathIdx < paths.size(); pathIdx++) { Path path = paths.get(pathIdx); if (path.pathDone) { // this path was already entered into the map! continue; } // No route between the endpoints was found for this path if (path.nodesX == null || path.pathUnroutable) { if(DEBUG) { System.err.printf("Net \"%s\": Path routing failure! totalCost %d, Path will be left untouched.\n", path.segment.getNetName(), path.totalCost); } if (!unroutablePathFound){ ++unroutableNetCount; unroutablePathFound = true; } unroutablePathCount++; // ignore this path from now on! path.pathUnroutable = true; path.pathDone = true; net.pathDone[pathIdx] = true; continue; } for (int i = 0; i < path.nodesX.length; ++i) { int status = map.getStatus(path.nodesX[i], path.nodesY[i], path.nodesZ[i]); if (status != Map.CLEAR && status != net.getNetID()) { // Path is invalid because it's using blocked nodes invalidFound = true; pathInvalid[pathIdx] = true; break; } } // only invalid paths need to be recomputed if (!pathInvalid[pathIdx]) { net.pathDone[pathIdx] = true; path.pathDone = true; // The path is ok, so we set the new blockages map.setStatus(path.nodesX, path.nodesY, path.nodesZ, net.getNetID()); } } shutdown = System.currentTimeMillis() > shutdownTime; if (invalidFound) { // There were invalid (but not unroutable) paths, so reroute them ++invalidNetSum; if (DEBUG){ int netInvalidLength =0; int invalidPathCount = 0; for (Path p: paths) { if (!p.pathDone && !p.pathUnroutable) { netInvalidLength += p.totalCost; invalidPathCount++; } } invalidPathSum += invalidPathCount; invalidLength += netInvalidLength; System.out.printf("AStarMaster: Net %3d contains %d invalid paths, rerouting it, invalid length: %d (net est.: %4d), invalid nets: %d, completed:%d/%d\n", net.getElectricNetID(), invalidPathCount, netInvalidLength, net.getLengthEstimate(), invalidNetSum, completedNetCount, netList.size()); } if (!shutdown) { Goal goal = new Goal(net, map); AStarWorker worker = new AStarWorker(net, nodePools, storagePools, map, goal, shutdownTime); // Do it again netCompletionService.submit(worker); } else { // need to shutdown, so finish valid paths in this net for (Path path : paths) { if (path.pathDone && !path.pathUnroutable) { routeSegment(path); } ++completedPathCount; } ++completedNetCount; activeNetList.remove(net); if (DEBUG) { System.out.printf("AStarMaster: shutdown now, time after shutdown threshold:%dms (Net %3d is complete, completed nets:%3d/%d, completed paths:%3d/%d)\n", System.currentTimeMillis() - shutdownTime, net.getElectricNetID(), completedNetCount, netList.size(), completedPathCount, totalNumPaths); } } } else { // All paths were valid/unroutable, so finish this net and schedule the next for (Path path : paths) { if (path.pathDone && !path.pathUnroutable) { routeSegment(path); } ++completedPathCount; } ++completedNetCount; if (DEBUG) System.out.printf("AStarMaster: Net %3d is complete, completed nets:%3d/%d, completed paths:%3d/%d\n", net.getElectricNetID(), completedNetCount, netList.size(), completedPathCount, totalNumPaths); activeNetList.remove(net); if (!shutdown) { scheduleUnroutedNet(); } } } catch (InterruptedException e) { System.err.printf("AStarMaster: Caught exception in Worker:\n%s\n", e.toString()); e.getCause().printStackTrace(); return; } catch (ExecutionException e) { System.err.printf("AStarMaster: Caught exception in Worker:\n%s\n", e.toString()); e.getCause().printStackTrace(); return; } } assert activeNetList.isEmpty(); if (DEBUG) { long currentTime = System.currentTimeMillis(); System.out.printf("\nAStarMaster: Routing completed after %d ms, invalid/completed nets: %d/%d (%.1f %%), invalid/completed paths: %d/%d (%.1f %%)\n", currentTime - startTime, invalidNetSum, completedNetCount, (100f * invalidNetSum) / (completedNetCount), invalidPathSum, completedPathCount, (100f * invalidPathSum) / (completedPathCount)); masterTimeActiveSum += currentTime - masterTimeActiveStart; System.out.printf("AStarMaster: Master thread waiting time: %d, active time: %d (%.1f%%)\n", masterTimeWaitingSum, masterTimeActiveSum, masterTimeActiveSum*100f / (currentTime - startTime)); } if (DEBUG) { if (unroutableNetCount > 0) System.err.printf("Error: %d nets not routed, containing %d paths\n", unroutableNetCount, unroutablePathCount); evaluateRouting(invalidLength); } } /** * looks at all Paths and marks all that were set pathUnroutable by EndpointMarker to pathDone, * so that they will be ignored by Worker */ private void processUnroutables() { for (Net net : netList) { List<Path> paths = net.getPaths(); boolean unroutablePathFound = false; // Check all paths routed for validity for (int pathIdx = 0; pathIdx < paths.size(); pathIdx++) { Path path = paths.get(pathIdx); // DEBUG: this should not happen, pathDone should not be set before this loop assert !path.pathDone : "processUnroutables(): pathDone was already set!"; // No route between the endpoints was found for this path if (path.pathUnroutable) { if (DEBUG) { System.err.printf("Net \"%s\": Path unroutable, Path will be left untouched.\n", path.segment.getNetName()); } if (!unroutablePathFound) { ++unroutableNetCount; unroutablePathFound = true; } unroutablePathCount++; // ignore this path from now on! path.pathUnroutable = true; path.pathDone = true; net.pathDone[pathIdx] = true; } } } } /** Starts the execution of a net from the unrouted list, moving it to the active list */ private void scheduleUnroutedNet() { if(unroutedNetList.isEmpty()) return; long startTime = 0; if(DEBUG) startTime = System.nanoTime(); // Determine the net with least overlap to the currently routed Net net = null; int minSum = Integer.MAX_VALUE; for(Net unroutedNet : unroutedNetList) { int sum = 0; for(Net activeNet : activeNetList) { sum += activeNet.getOverlapSum(unroutedNet); } if(sum < minSum) { minSum = sum; net = unroutedNet; if(minSum == 0) break; } } if(DEBUG) { if(minSum > 0) System.out.printf("AStarMaster: Net %d scheduled with overlap %d after %.3f ms\n", net.getElectricNetID(), minSum, (System.nanoTime()-startTime)/1e6f); } unroutedNetList.remove(net); activeNetList.add(net); Goal goal = new Goal(net, map); AStarWorker worker = new AStarWorker(net, nodePools, storagePools, map, goal, shutdownTime); netCompletionService.submit(worker); } /** * Method to do routing * * @param segmentsToRoute * a list of all routes that need to be made. * @param allLayers * a list of all layers that can be used in routing. * @param allNodes * a list of all nodes involved in the routing. * @param allContacts * a list of all contacts that can be used in routing. */ protected void runRouting(Cell cell, List<RoutingSegment> segmentsToRoute, List<RoutingLayer> allLayers, List<RoutingContact> allContacts, List<RoutingGeometry> blockages) { netList = new ArrayList<Net>(); HashMap<Integer, Net> netMap = new HashMap<Integer, Net>(); this.totalNumPaths = segmentsToRoute.size(); // Create nets to combine the given segments for (RoutingSegment rs : segmentsToRoute) { int netID = rs.getNetID(); Net net = netMap.get(netID); if (net == null) { net = new Net(rs.getNetID()); netMap.put(rs.getNetID(), net); netList.add(net); } net.getPaths().add(new Path(rs, dispX, dispY, map.getScalingFactor())); } sortNets(); unroutedNetList = new LinkedList<Net>(netList); this.allContacts = allContacts; run(); } /** Calculate some statistic information about the routing process */ private void evaluateRouting(int invalidLength) { int sum = 0; int estimate = 0; int netSum, netEstimate; int diff; //difference between optimum and actual cost for (Net net: netList) { netSum = 0; for (Path p: net.getPaths()) { if (p.pathDone && !p.pathUnroutable) { netSum += p.totalCost; } } sum += netSum; netEstimate = net.getRoutableLengthEstimate(); estimate += netEstimate; } diff = sum-estimate; System.out.printf("total routing cost: %d, estimated: %d, diff: %d (%.02f%%), invalid length: %d (%.02f%%)\n", sum, estimate, diff, diff*100f/estimate, invalidLength, invalidLength*100f/sum); } /** Sort the nets by length to improve invalid routing costs */ private void sortNets() { long start = 0; if (DEBUG) { start = System.currentTimeMillis(); } Collections.sort(netList, new Comparator<Net>() { public int compare(Net n1, Net n2) { int len1 = n1.getLengthEstimate(); int len2 = n2.getLengthEstimate(); return (len1 - len2); } }); if (DEBUG) { System.out.printf("Master: sortNets() took %d ms for %d nets\n", System.currentTimeMillis() - start, netList.size()); } } /** Finally insert the path into the Electric data structures */ private void routeSegment(Path path) { /* long start; if (DEBUG) { start = System.currentTimeMillis(); } */ RoutingSegment segment = path.segment; int[] nodesX = path.nodesX; int[] nodesY = path.nodesY; int[] nodesZ = path.nodesZ; Point2D startLocation = segment.getStartEnd().getLocation(); Point2D finishLocation = segment.getFinishEnd().getLocation(); // Now that we have the result, we convert the path to wires and // wire ends and add them to the segment // Special handling for the start point RoutePoint previous = new RoutePoint(RoutingContact.STARTPOINT, startLocation, 0); segment.addWireEnd(previous); RoutingLayer layer = metalLayers[nodesZ[0]]; RoutingContact contact = metalPins[nodesZ[0]]; double scalingFactor = map.getScalingFactor(); // Determine quadrant of start / finish point boolean startRight = path.startRight; boolean startAbove = path.startAbove; boolean finishRight = path.finishRight; boolean finishAbove = path.finishAbove; // A complicated scheme follows that carefully handles routing at the endpoints // special handling for all Paths shorter than 4 needed to avoid Notch errors if(nodesX.length < 4) { // Short nets need special care to avoid notch errors assert nodesX.length >= 1 : nodesX.length; //0: no connection, 1: L, 2: horizontal Z, 3: vertical Z, 4: M int connectionMode; if(nodesX.length == 1) { // Diagonal? if(startRight != finishRight && startAbove != finishAbove) { // Make Z connection connectionMode = 2; } else { // Make L connection connectionMode = 1; } } else if(nodesX.length == 2) { boolean horizontal = nodesY[0] == nodesY[1]; boolean vertical = nodesX[0] == nodesX[1]; boolean startInside = (horizontal && ((nodesX[0] < nodesX[1]) == startRight)) || (vertical && ((nodesY[0] < nodesY[1]) == startAbove)); boolean finishInside = (horizontal && ((nodesX[0] > nodesX[1]) == finishRight)) || (vertical && ((nodesY[0] > nodesY[1]) == finishAbove)); boolean sameSide = (vertical && (startRight == finishRight)) || (horizontal && (startAbove == finishAbove)); if(startInside && finishInside || sameSide) { // Make L connection connectionMode = 1; } else { // Make Z connection if(horizontal) connectionMode = 2; else connectionMode = 3; } } else { assert nodesX.length == 3 : nodesX.length; if(nodesX[0] == nodesX[2]) // Make Z connection connectionMode = 3; else if(nodesY[0] == nodesY[2]) // Make Z connection connectionMode = 2; else { // Not straight int quadrantStartX = (int)((startLocation.getX() + dispX) / (scalingFactor / 2)); int quadrantStartY = (int)((startLocation.getY() + dispY) / (scalingFactor / 2)); int quadrantFinishX = (int)((finishLocation.getX() + dispX) / (scalingFactor / 2)); int quadrantFinishY = (int)((finishLocation.getY() + dispY) / (scalingFactor / 2)); double middleX = getUnscaledCoordinate(nodesX[1], dispX, scalingFactor); double middleY = getUnscaledCoordinate(nodesY[1], dispY, scalingFactor); if(Math.abs(quadrantStartX - quadrantFinishX) <= 1 || Math.abs(quadrantStartY - quadrantFinishY) <= 1) { // Make L connection connectionMode = 1; } else if(Math.abs(startLocation.getX() - middleX) <= scalingFactor || Math.abs(finishLocation.getX() - middleX) <= scalingFactor) { // Make Z connection connectionMode = 3; } else if(Math.abs(startLocation.getY() - middleY) <= scalingFactor || Math.abs(finishLocation.getY() - middleY) <= scalingFactor) { // Make Z connection connectionMode = 2; } else { // Make M connection connectionMode = 4; } } } if(connectionMode == 1) { // Make L connection RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), finishLocation.getY()), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } else if(connectionMode == 2) { // Make horizontal Z connection double pointY = getUnscaledCoordinate((nodesX.length == 3 ? nodesY[1] : nodesY[0]), dispY, scalingFactor); { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(connectionMode == 3) { // Make vertical Z connection double pointX = getUnscaledCoordinate((nodesX.length == 3 ? nodesX[1] : nodesX[0]), dispX, scalingFactor); { RoutePoint point = new RoutePoint(contact, new Point2D.Double(pointX, startLocation.getY()), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(pointX, finishLocation.getY()), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(connectionMode == 4) { // Make M connection assert nodesX.length == 3; double pointX = getUnscaledCoordinate(nodesX[1], dispX, scalingFactor); double pointY = getUnscaledCoordinate(nodesY[1], dispY, scalingFactor); { RoutePoint point; if(nodesX[0] == nodesX[1]) point = new RoutePoint(contact, new Point2D.Double(pointX, startLocation.getY()), 0); else point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(pointX, pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point; if(nodesX[2] == nodesX[1]) point = new RoutePoint(contact, new Point2D.Double(pointX, finishLocation.getY()), 0); else point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } } else { // nodesX.length >= 4 int startOuterX = startRight ? nodesX[0]-1 : nodesX[0]+1; int startInnerX = startRight ? nodesX[0]+1 : nodesX[0]-1; int startOuterY = startAbove ? nodesY[0]-1 : nodesY[0]+1; int startInnerY = startAbove ? nodesY[0]+1 : nodesY[0]-1; int finishOuterX = finishRight ? nodesX[nodesX.length-1]-1 : nodesX[nodesX.length-1]+1; int finishInnerX = finishRight ? nodesX[nodesX.length-1]+1 : nodesX[nodesX.length-1]-1; int finishOuterY = finishAbove ? nodesY[nodesX.length-1]-1 : nodesY[nodesX.length-1]+1; int finishInnerY = finishAbove ? nodesY[nodesX.length-1]+1 : nodesY[nodesX.length-1]-1; double startGridX = getUnscaledCoordinate(nodesX[0], dispX, scalingFactor); double startGridY = getUnscaledCoordinate(nodesY[0], dispY, scalingFactor); double startInnerGridY = getUnscaledCoordinate(startInnerY, dispY, scalingFactor); double finishGridX = getUnscaledCoordinate(nodesX[nodesX.length-1], dispX, scalingFactor); double finishGridY = getUnscaledCoordinate(nodesY[nodesX.length-1], dispY, scalingFactor); double finishInnerGridY = getUnscaledCoordinate(finishInnerY, dispY, scalingFactor); if(nodesX[1] == startOuterX) { // Vertical or via? if(nodesX[2] == nodesX[1]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(nodesY[1] == startOuterY) { { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } // Horizontal or via? if(nodesY[2] == nodesY[1]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startGridX, startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(nodesX[1] == startInnerX) { if(nodesY[2] == startInnerY) { if(nodesY[3] != nodesY[2]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startInnerGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } // Vertical or via? else if(nodesX[2] == nodesX[1]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if (nodesY[1] == startInnerY) { // Vertical or via? if(nodesX[2] == nodesX[1]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startInnerGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else { assert nodesZ[1] != nodesZ[0]; { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startLocation.getX(), startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(startGridX, startGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } // Iterate over all intermediate positions for (int i = 1; i < nodesX.length - 1; ++i) { // look out for layer changes if (nodesZ[i - 1] == nodesZ[i]) { if (i > 1 && i < (nodesX.length - 2)) { // If this is part of a long line, don't create a redundant // route point int x = nodesX[i]; if (x == nodesX[i - 1] && x == nodesX[i + 1]) continue; int y = nodesY[i]; if (y == nodesY[i - 1] && y == nodesY[i + 1]) continue; } // connection is on same layer contact = metalPins[nodesZ[i]]; } else { contact = getVia(metalLayers[nodesZ[i - 1]], metalLayers[nodesZ[i]]); } // SCALE! double pointX = getUnscaledCoordinate(nodesX[i], dispX, scalingFactor); double pointY = getUnscaledCoordinate(nodesY[i], dispY, scalingFactor); if(i == 1) { if(nodesX[1] == startOuterX) { // Horizontal? if(nodesX[2] != nodesX[1]) { pointX = startLocation.getX(); } } else if(nodesY[1] == startOuterY) { // Vertical? if(nodesY[2] != nodesY[1]) { pointY = startGridY; } } else if(nodesX[1] == startInnerX) { if(nodesY[2] == startInnerY) { // Vertical? if(nodesY[3] != nodesY[2]) { pointY = startInnerGridY; } else { pointX = startLocation.getX(); pointY = startInnerGridY; } } // Horizontal? else if(nodesX[2] != nodesX[1]) { pointX = startLocation.getX(); } } else if (nodesY[1] == startInnerY) { // Horizontal? if(nodesX[2] != nodesX[1]) { pointX = startLocation.getX(); } } } else if(i == (nodesX.length - 2)) { if(nodesX[nodesX.length-2] == finishOuterX) { // Horizontal? if(nodesX[nodesX.length-3] != nodesX[nodesX.length-2]) { pointX = finishLocation.getX(); } } else if(nodesY[nodesX.length-2] == finishOuterY) { // Vertical? if(nodesY[nodesX.length-3] != nodesY[nodesX.length-2]) { pointY = finishGridY; } } else if(nodesX[nodesX.length-2] == finishInnerX) { if(nodesY[nodesX.length-3] == finishInnerY) { // Vertical? if(nodesY[nodesX.length-4] != nodesY[nodesX.length-3]) { pointY = finishInnerGridY; } else { pointX = finishLocation.getX(); pointY = finishInnerGridY; } } // Horizontal? else if(nodesX[nodesX.length-3] != nodesX[nodesX.length-2]) { pointX = finishLocation.getX(); } } else if (nodesY[nodesX.length-2] == finishInnerY) { // Horizontal? if(nodesX[nodesX.length-3] != nodesX[nodesX.length-2]) { pointX = finishLocation.getX(); } } } RoutePoint point = new RoutePoint(contact, new Point2D.Double(pointX, pointY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); layer = metalLayers[nodesZ[i]]; previous = point; } layer = metalLayers[nodesZ[nodesX.length-1]]; contact = metalPins[nodesZ[nodesX.length-1]]; // Special handling for the finish point if(nodesX[nodesX.length-2] == finishOuterX) { // Vertical or via? if(nodesX[nodesX.length-3] == nodesX[nodesX.length-2]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(nodesY[nodesX.length-2] == finishOuterY) { // Horizontal or via? if(nodesY[nodesX.length-3] == nodesY[nodesX.length-2]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishGridX, finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if(nodesX[nodesX.length-2] == finishInnerX) { if(nodesY[nodesX.length-3] == finishInnerY) { if(nodesY[nodesX.length-4] != nodesY[nodesX.length-3]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishInnerGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } // Vertical or via? else if(nodesX[nodesX.length-3] == nodesX[nodesX.length-2]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else if (nodesY[nodesX.length-2] == finishInnerY) { // Vertical or via? if(nodesX[nodesX.length-3] == nodesX[nodesX.length-2]) { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishInnerGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } else { assert nodesZ[nodesX.length-2] != nodesZ[nodesX.length-1]; { RoutePoint point = new RoutePoint(getVia(metalLayers[nodesZ[nodesX.length-2]], metalLayers[nodesZ[nodesX.length-1]]), new Point2D.Double(finishGridX, finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(metalLayers[nodesZ[nodesX.length-2]], previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } { RoutePoint point = new RoutePoint(contact, new Point2D.Double(finishLocation.getX(), finishGridY), 0); segment.addWireEnd(point); RouteWire wire = new RouteWire(layer, previous, point, layer.getMinWidth()); segment.addWire(wire); previous = point; } } } RoutePoint finishPoint = new RoutePoint(RoutingContact.FINISHPOINT, finishLocation, 0); segment.addWireEnd(finishPoint); RouteWire wire = new RouteWire(layer, previous, finishPoint, layer.getMinWidth()); segment.addWire(wire); /* if (DEBUG) { System.out.printf("Master: routeSegment(Path %s) took %d ms\n", path.segment.getNetName(), System.currentTimeMillis() - start); } */ } /** * @return Coordinate inversely scaled, corrected by dispX or dispY and shifted to the middle of the "grid" */ private double getUnscaledCoordinate(int scaledCoord, int disp, double scalingFactor) { double shift = scalingFactor / 2d; return (scaledCoord*scalingFactor) - disp + shift; } /** @return The routing contact to route between the given layers */ private RoutingContact getVia(RoutingLayer l1, RoutingLayer l2) { for (RoutingContact rc : allContacts) { if ((rc.getFirstLayer().equals(l1) && rc.getSecondLayer().equals(l2)) || (rc.getFirstLayer().equals(l2) && rc.getSecondLayer().equals(l1))) { return rc; } } return null; } }