All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.tool.routing.VerticalRoute Maven / Gradle / Ivy

/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: VerticalRoute.java
 *
 * Copyright (c) 2003, 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;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.geometry.PolyMerge;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.PrimitivePort;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.user.User;
import com.sun.electric.util.math.EDimension;

/**
 * Class to route vertically (in Z direction) between two RouteElements.
 * The class is used as following:
 * 

After creating the object, call specifyRoute() to find a way to connect * between startRE and endRE RouteElement objects. At this point you may wish to * use the information about the specified route before actually building the route. * Right now the only useful information that is exported is the start and end ArcProtos * used, if not already specified. *

Once satisfied with the specification, call buildRoute() to create all * the RouteElements that determine exactly what the route will look like. Note * that this does not actually create any objects, it just creates a Route, which * can then be used to create Electric database objects. *

There are two forms of build route, the first tries to figure out everything * for you (contact sizes, arc angles), and connects to startRE and endRE if given. * The second just creates RouteElements from the specification, and you need to give * it the contact size and arc angle, and it does not connect to startRE or endRE. */ public class VerticalRoute { /** start of the vertical route */ private PortProto startPort; /** end of the vertical route */ private PortProto endPort; /** list of arcs and nodes to make route */ private SpecifiedRoute specifiedRoute; /** list of all valid specified routes */ private List allSpecifiedRoutes; /** first arc (from startRE) */ private ArcProto startArc; /** last arct (to endRE) */ private ArcProto endArc; /** list of contacts to use */ private List contacts; /** the possible start arcs */ private ArcProto [] startArcs; /** the possible end arcs */ private ArcProto [] endArcs; /** if route specification succeeded */ private boolean specificationSucceeded; private int searchNumber; private static final int SEARCHLIMIT = 3000; private static final boolean DEBUG = false; private static final boolean DEBUGSEARCH = false; private static final boolean DEBUGTERSE = false; private static class SpecifiedRoute extends ArrayList { ArcProto startArc; ArcProto endArc; void printRoute() { for (int k=0; k width) width = startArcWidth; if (startArcAngle == 0 && startArcWidth > height) height = startArcWidth; if (endArcAngle == 900 && endArcWidth > width) width = endArcWidth; if (endArcAngle == 0 && endArcWidth > height) height = endArcWidth; size = new Dimension2D.Double(width, height); } for (RouteElement re : vertRoute) { if (re instanceof RouteElementPort) ((RouteElementPort)re).setNodeSize(size); if (!route.contains(re)) route.add(re); } } */ /** * Builds a Route using the specification from specifyRoute(), but without * connecting to startRE and endRE. The start of the returned Route can connect * to startRE, and the end of the returned Route can connect to endRE. * The caller must handle the final connections. * @param cell the Cell in which to create the route * @param location where in the database the vertical route is to be created * @param contactSize the size of contacts * @param arcAngle angle of zero length arcs created between contacts (usually zero) * @param stayInside a polygonal area in which the new arc must reside (if not null). * @param ep EditingPreferences with default sizes * @return a Route whose start can connect to startRE and whose end * can connect to endRE. Returns null if no specification for the route exists. */ public Route buildRoute(Cell cell, Point2D location, EDimension contactSize, int arcAngle, PolyMerge stayInside, EditingPreferences ep) { if (specifiedRoute == null) { System.out.println("Error: Trying to build VerticalRoute without a call to specifyRoute() first"); return null; } Route route = new Route(); if (specifiedRoute.size() == 0) return route; if (DEBUG) { System.out.println("Building route: "); for (Object obj : specifiedRoute) { System.out.println(" "+obj); } } // pull off the first object, which will be a port, and create contact from that PrimitivePort pp = (PrimitivePort)specifiedRoute.remove(0); RouteElementPort node = RouteElementPort.newNode(cell, pp.getParent(), pp, location, contactSize.getWidth(), contactSize.getHeight(), ep); route.add(node); route.setStart(node); route.setEnd(node); // now iterate through rest of list and create arc,port route element pairs for (Iterator it = specifiedRoute.iterator(); it.hasNext(); ) { ArcProto ap = (ArcProto)it.next(); PrimitivePort port = (PrimitivePort)it.next(); // create node RouteElementPort newNode = RouteElementPort.newNode(cell, port.getParent(), port, location, contactSize.getWidth(), contactSize.getHeight(), ep); route.add(newNode); route.setEnd(newNode); // create arc //double arcWidth = Router.getArcWidthToUse(node, ap, arcAngle); ImmutableArcInst defA = ap.getDefaultInst(ep); double arcWidth = ap.getDefaultLambdaBaseWidth(ep); RouteElementArc arc = RouteElementArc.newArc(cell, ap, arcWidth, node, newNode, location, location, null, null, null, defA.isHeadExtended(), defA.isTailExtended(), stayInside); arc.setArcAngle(arcAngle); route.add(arc); node = newNode; } return route; } /** * Specify the route */ private boolean specifyRoute(ArcProto [] startArcs, ArcProto [] endArcs) { specifiedRoute = new SpecifiedRoute(); allSpecifiedRoutes = new ArrayList(); this.startArc = null; this.endArc = null; // try to find a way to connect, do exhaustive search for (int i=0; i zeroLengthRoutes = new ArrayList(); for (int i=0; i 0) { for (SpecifiedRoute r : zeroLengthRoutes) { if (r.startArc == User.getUserTool().getCurrentArcProto()) specifiedRoute = r; } } allSpecifiedRoutes.clear(); startArc = specifiedRoute.startArc; endArc = specifiedRoute.endArc; if (DEBUGSEARCH || DEBUGTERSE) { System.out.println("*** Using Best Route: "); specifiedRoute.printRoute(); } return true; } /** * Method to check whether an equivalent PortProto has been added to the list. * @param pp * @return */ private boolean isPortProtoContained(Object pp) { if (specifiedRoute.contains(pp)) return true; // exactly the same port if (!(pp instanceof PrimitivePort)) return false; // not a concern PrimitivePort ppp = (PrimitivePort)pp; List equivalent = User.getUserTool().getEquivalentPorts(ppp); if (equivalent != null) { for (PrimitivePort p : equivalent) { if (specifiedRoute.contains(p)) return true; } } return false; } /** * Recursive method to create a specification list of ports and arcs * that connect startArc to endArc. The list will be odd in length * (or zero if startArc and endArc are the same). It will consist * of a PortProto, and zero or more ArcProto,PortProto pairs in that order. * The first PortProto will be able to connect to the initial startArc, * and the last PortProto will be able to connect to the final endArc. *

PortProtos used are Ports from the current technology whose parents * (NodeProtos) have the function of CONTACT. * @param startArc connect from this arc * @param endArc connect to this arc * @param ds spacing for debug messages, if enabled */ private void findConnectingPorts(ArcProto startArc, ArcProto endArc, StringBuffer ds) { // throw away route if it's longer than shortest good route if (specifiedRoute.size() > getShortestRouteLength()) return; if (startArc == endArc) { saveRoute(specifiedRoute); if (DEBUGTERSE) System.out.println(" --Found good route of length "+specifiedRoute.size()); return; // don't need anything to connect between them } ds.append(" "); if (searchNumber > SEARCHLIMIT) { return; } if (searchNumber == SEARCHLIMIT) { System.out.println("Search limit reached in VerticalRoute"); searchNumber++; return; } searchNumber++; Technology tech = startArc.getTechnology(); PrimitivePort pp = User.getUserTool().getPreferredContactPortProto(startArc, endArc); if (pp != null) { if (DEBUGSEARCH) System.out.println(ds+"Checking if "+pp+" connects between "+startArc+" and "+endArc); specifiedRoute.add(pp); saveRoute(specifiedRoute); return; } // see if we can find a port in the current technology // that will connect the two arcs // for (Iterator nodesIt = tech.getNodes(); nodesIt.hasNext(); ) { // PrimitiveNode pn = nodesIt.next(); // //for (PrimitiveNode pn : contacts) { // // ignore anything that is not CONTACT // if (!pn.getFunction().isContact()) continue; // if (pn.isNotUsed()) continue; // // for (Iterator portsIt = pn.getPorts(); portsIt.hasNext(); ) { // PrimitivePort ppp = (PrimitivePort)portsIt.next(); // if (DEBUGSEARCH) System.out.println(ds+"Checking if "+ppp+" connects between "+startArc+" and "+endArc); // if (ppp.connectsTo(startArc) && ppp.connectsTo(endArc)) { // specifiedRoute.add(ppp); // if (ppp != pp) // System.out.println("something diff"); // saveRoute(specifiedRoute); // return; // this connects between both arcs // } // } // } // try all contact ports as an intermediate // for (Iterator nodesIt = tech.getNodes(); nodesIt.hasNext(); ) // { // PrimitiveNode pn = nodesIt.next(); // //for (PrimitiveNode pn : contacts) { // // ignore anything that is not CONTACT // if (!pn.getFunction().isContact()) continue; // if (pn.isNotUsed()) continue; // // for (Iterator portsIt = pn.getPorts(); portsIt.hasNext(); ) // { // pp = (PrimitivePort)portsIt.next(); List portsList = User.getUserTool().getPrimitivePortConnectedToArc(startArc); for (PrimitivePort p : portsList) { pp = p; if (DEBUGSEARCH) System.out.println(ds+"Checking if "+pp+" (parent is "+pp.getParent()+") connects to "+startArc); assert(pp.connectsTo(startArc)); // if (pp.connectsTo(startArc)) { if (pp == startPort) continue; // ignore start port if (pp == endPort) continue; // ignore end port if (isPortProtoContained(pp)) // if (specifiedRoute.contains(pp)) continue; // ignore ones we've already hit // add to list int prePortSize = specifiedRoute.size(); // pp = User.getUserTool().getCurrentContactPortProto(pp); // get the equivalent specifiedRoute.add(pp); // now try to connect through all arcs that can connect to the found pp int preArcSize = specifiedRoute.size(); ArcProto [] arcs = pp.getConnections(); for (int i=0; i 0) // { // boolean notSameStart = false; // for (Iterator itP = tryarc.findPinProto().getPrimitivePorts(); itP.hasNext();) // { // PrimitivePort p = itP.next(); // if (p == startPort) // { // notSameStart = true; // passing for the same port, avoiding loops // } // } // if (notSameStart) // continue; // } specifiedRoute.add(tryarc); if (DEBUGSEARCH) System.out.println(ds+"...found intermediate node "+pp+" through "+startArc+" to "+tryarc); // recurse findConnectingPorts(tryarc, endArc, ds); // remove added arcs and port and continue search while (specifiedRoute.size() > preArcSize) { specifiedRoute.remove(specifiedRoute.size()-1); } } // that port didn't get us anywhere, clear list back to last good point while (specifiedRoute.size() > prePortSize) { specifiedRoute.remove(specifiedRoute.size()-1); } } // } } if (DEBUGSEARCH) System.out.println(ds+"--- Bad path ---"); return; // no valid path to endpp found } /** * Save a successful route * @param route the route to save */ private void saveRoute(SpecifiedRoute route) { // create copy and store it if (DEBUGSEARCH) { System.out.println("** Found Route for: startArc="+route.startArc+", endArc="+route.endArc); route.printRoute(); } int shortestLength = getShortestRouteLength(); if (route.size() > shortestLength) { // ignore it return; } SpecifiedRoute loggedRoute = new SpecifiedRoute(); loggedRoute.startArc = route.startArc; loggedRoute.endArc = route.endArc; loggedRoute.addAll(route); allSpecifiedRoutes.add(loggedRoute); boolean trim = true; while (trim) { // remove shorter routes Iterator it = null; for (it = allSpecifiedRoutes.iterator(); it.hasNext(); ) { SpecifiedRoute r = it.next(); if (r.size() > shortestLength) { allSpecifiedRoutes.remove(r); break; } } if (!it.hasNext()) { trim = false; // done trimming } } } /** * Get the length of the shortest route. */ private int getShortestRouteLength() { // Because all routes should be of the // shortest length, just return the length of the first route if (allSpecifiedRoutes.size() == 0) return Integer.MAX_VALUE; SpecifiedRoute r = allSpecifiedRoutes.get(0); return r.size(); } }