/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Wiring.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.awt.geom.Point2D; import java.util.HashMap; import java.util.LinkedList; import java.util.List; 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.RoutingLayer; import com.sun.electric.tool.routing.RoutingFrame.RoutingSegment; import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.Tupel; /** * This class offers functions to create wires in electric out of created routes and between tupels. */ public class Wiring { private static boolean DEBUG = false; protected static final boolean REPORTING = true; private static HashMap<String, Integer> metalLayerMap; private static List<RoutingLayer> allLayers; private static List<RoutingContact> allContacts; public static void init(List<RoutingLayer> layers, HashMap<String, Integer> map, List<RoutingContact> allContacts, boolean output) { DEBUG = output; metalLayerMap = map; allLayers = layers; Wiring.allContacts = allContacts; } /** * Connect two tupels. ATTENTION: they have to be on the same layer! * This method is only suited for connecting connectionPoints. * @param rs RoutingSegment where wire should be created * @param tA first tupel * @param tB second tupel * @return RoutePoints created at the tupels' positions */ public static RoutePoint[] connect(RoutingSegment rs, Tupel tA, Tupel tB) { RoutingLayer layer = getRoutingLayerByTupelLayer(tA.getLayer()); RoutePoint r1 = placePin(tA.getLayer(), tA); RoutePoint r2 = placePin(tB.getLayer(), tB); connectRoutePoints(rs, r1, r2, layer); RoutePoint[] result = {r1, r2}; return result; } /** * Connect two route points. * @param rs routing segment where wire is created * @param rp1 first route point * @param rp2 second route point */ public static void connect(RoutingSegment rs, RoutePoint rp1, RoutePoint rp2){ connectRoutePoints(rs, rp1, rp2, rp1.getContact().getFirstLayer()); } /** * Place route points at the location given by the two tupels. * @param tA first tupel * @param tB second tupel * @return */ public static RoutePoint[] getRoutePoints(Tupel tA, Tupel tB) { RoutePoint r1 = placePin(tA.getLayer(), tA); RoutePoint r2 = placePin(tB.getLayer(), tB); RoutePoint[] result = {r1, r2}; return result; } /** * Connects two route points of a routing segment lying on the same layer. This method is synchronized! * @param rs RoutingSegment * @param r1 first RoutePoint * @param r2 second RoutePoint * @param layer RoutingLayer */ synchronized private static void connectRoutePoints(RoutingSegment rs, RoutePoint r1, RoutePoint r2, RoutingLayer layer) { if (DEBUG) { System.out.println("WIRING: Verbinde " + r1.getLocation() + "->" + r2.getLocation()); } rs.addWireEnd(r1); rs.addWireEnd(r2); RouteWire rw = new RouteWire(layer, r1, r2, layer.getMinWidth()); rs.addWire(rw); } /** * Calls addWire and connects two routing points on the same layer. * @param rs RoutingSegment where wire should be created * @param r1 first RoutePoint * @param r2 second RoutePoint * @param layer on which wire is created */ private static void createWire(RoutingSegment rs, RoutePoint r1, RoutePoint r2, RoutingLayer layer) { if (DEBUG) { System.out.println("createWire@WIRING: Verbinde " + r1.getLocation() + "->" + r2.getLocation()+" auf Layer "+layer.getName()); } RouteWire rw = new RouteWire(layer, r1, r2, layer.getMinWidth()); rs.addWire(rw); } // public static void connect(RoutingPart rp,List<Tupel> edgePoints) { // RoutingSegment rs=rp.rs; // Point2D start=rs.getStartEnd().getLocation(); // Point2D end=rs.getFinishEnd().getLocation(); // RoutePoint rp1; // int i=0; // if(containsStart(rs,edgePoints)){ // rp1=new RoutePoint(RoutingContact.STARTPOINT, start, 0); // rs.addWireEnd(rp1); // // }else{ // Tupel t1=edgePoints.get(0); // RoutingLayer l=getRoutingLayerByTupelLayer(t1.getLayer()); // rp1=new RoutePoint(l.getPin(),new Point2D.Double(t1.getX_InsideElectric(), t1.getY_InsideElectric()),0); // //rs.addWireEnd(rp1);//TODO: rein? // if (REPORTING) SimpleQualityReporter.addPin(); // i++;//TODO: weg? // } // // for (;i<edgePoints.size()-1;i++) { // Tupel t1=edgePoints.get(i); // Tupel t2=edgePoints.get(i+1); // //routing points are on same position but different layers so we need a via here // if(t1.isEqualPosition(t2) && t1.getLayer()!=t2.getLayer()){ // RoutingLayer rl1 = getRoutingLayerByTupelLayer(t1.getLayer()); // RoutingLayer rl2 = getRoutingLayerByTupelLayer(t2.getLayer()); // RoutePoint via=placeVia(rl1,rl2,t1.getX_InsideElectric(),t1.getY_InsideElectric()); // if (REPORTING) SimpleQualityReporter.addVia(); // connectRoutePoints(rs, rp1, via, rl1); // rp1=via; // } // } // Tupel last=edgePoints.get(edgePoints.size()-1); // //last routing point was NOT a via // //create a new routing point located at the location of the last tupel // //connect it with last via and make it new last routing point // if(!(last.isEqualPosition(rp1))){ // RoutingLayer layer=getRoutingLayerByTupelLayer(last.getLayer()); // RoutePoint rp2=new RoutePoint(layer.getPin(),new Point2D.Double(last.getX_InsideElectric(),last.getY_InsideElectric()),0); // if (REPORTING) SimpleQualityReporter.addPin(); // connectRoutePoints(rs, rp1, rp2, layer); // rp1=rp2; // // } // //add a wire between last routing point and finish point // if(containsEnd(rs, edgePoints)){ // RoutePoint rp2=new RoutePoint(RoutingContact.FINISHPOINT, end, 0); // rs.addWireEnd(rp2); // connectRoutePoints(rs, rp1, rp2, rs.getFinishLayers().get(0)); // } // // } /** * Create wires between a list of tupels that symbolize the route of the given routing part. * @param rp RoutingPart * @param edgePoints list of tupels that build the route */ public static void connect(RoutingPart rp, List<Tupel> edgePoints) { boolean makeAngularWiresRectangular = true; if(DEBUG && rp.rs.getFinishEnd().getLocation().equals(new Point2D.Double(1929.2, 331.6))){ System.out.println("Have it..."); } LinkedList<WiringPart> contacts = new LinkedList<WiringPart>(); boolean lastContactWasVia = false; RoutePoint rp1 = rp.getStartRoutePoint(); boolean firstPoint = true; if(containsStart(rp.rs, edgePoints)){ firstPoint=false; } Tupel t1; Tupel t2; int i=0; t1 = edgePoints.get(i); t2 = edgePoints.get(i + 1); //first point is rounded start point if (makeAngularWiresRectangular && containsStart(rp.rs, edgePoints)) { boolean penultimateWireDirection = getWireDirection(t1, t2); RoutePoint rp2=null; if (penultimateWireDirection == WorkerThread.X_DIRECTION) { //we have to correct the second point of the routingpart so, that is at the same x-coordinate rp2=placeContact(rp.rs.getStartLayers().get(0), rp1.getLocation().getX(),t1.getY_InsideElectric()); } if (penultimateWireDirection == WorkerThread.Y_DIRECTION) { //we have to replace the last point so, that it has the same y-coordinate rp2=placeContact(rp.rs.getStartLayers().get(0),t1.getX_InsideElectric(), rp1.getLocation().getY()); } if(rp2==null && DEBUG) System.out.println("RP2 ist null"); contacts.add(new WiringPart(rp.rs.getStartLayers().get(0), rp1, rp2, firstPoint, false)); firstPoint=true; rp1=rp2; } for (i=1; i < edgePoints.size() - 1; i++) { t1 = edgePoints.get(i); t2 = edgePoints.get(i + 1); if (t1.isEqualPosition(t1) && (t1.getLayer() != t2.getLayer())) { //this is a via RoutePoint rp2 = placeVia(t1.getLayer(), t2.getLayer(), t1.getX_InsideElectric(), t1.getY_InsideElectric()); contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t1.getLayer()), rp1, rp2, firstPoint, false)); lastContactWasVia = true; rp1 = rp2; } else { if (!lastContactWasVia) { RoutePoint rp2 = placePin(t1.getLayer(), t1); contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t1.getLayer()), rp1, rp2, firstPoint, false)); lastContactWasVia = false; rp1 = rp2; } } firstPoint = true; } i=edgePoints.size()-1; t1 = edgePoints.get(i); t2 = edgePoints.get(i - 1); //last point is rounded end point if (makeAngularWiresRectangular && containsEnd(rp.rs, edgePoints)) { boolean penultimateWireDirection = getWireDirection(t1, t2); RoutePoint rp2=null; if (penultimateWireDirection == WorkerThread.X_DIRECTION) { //we have to correct the second point of the routingpart so, that is at the same x-coordinate rp2=placeContact(rp.rs.getFinishLayers().get(0), rp.getEndRoutePoint().getLocation().getX(),t1.getY_InsideElectric()); } if (penultimateWireDirection == WorkerThread.Y_DIRECTION) { //we have to replace the last point so, that it has the same y-coordinate rp2=placeContact(rp.rs.getFinishLayers().get(0),t1.getX_InsideElectric(), rp.getEndRoutePoint().getLocation().getY()); } if(rp2==null && DEBUG) System.out.println("RP2 ist null"); contacts.add(new WiringPart(rp.rs.getFinishLayers().get(0), rp1, rp2, firstPoint, false)); //firstPoint=true; rp1=rp2; } t2=edgePoints.get(edgePoints.size()-1); RoutePoint rp2 = rp.getEndRoutePoint(); boolean lastPoint=true; if(containsEnd(rp.rs, edgePoints)){ lastPoint=false; } contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t2.getLayer()), rp1, rp2, firstPoint, lastPoint)); wireRoutePoints(contacts, rp.rs); } /** * Create wire ends and wires for the routes. * @param routes list of routes to wire * @param rs RoutingSegment the wires are on */ private static void wireRoutePoints(List<WiringPart> routes, RoutingSegment rs) { for (WiringPart wiringPart : routes) { RoutePoint rp1 = wiringPart.getStart(); RoutePoint rp2 = wiringPart.getEnd(); if (!wiringPart.isAlreadyWired_start) { rs.addWireEnd(rp1); } if (!wiringPart.isAlreadyWired_end) { rs.addWireEnd(rp2); } createWire(rs, rp1, rp2, wiringPart.getLayer()); } } // private static RoutingLayer getCommonRoutingLayer(RoutePoint rp1, RoutePoint rp2, RoutingSegment rs) { // RoutingLayer rp1_fl = rp1.getContact().getFirstLayer(); // RoutingLayer rp1_sl = rp1.getContact().getSecondLayer(); // RoutingLayer rp2_fl = rp2.getContact().getFirstLayer(); // RoutingLayer rp2_sl = rp2.getContact().getSecondLayer(); // if (rp1_fl == null) { // rp1_fl = rp1_sl = rs.getStartLayers().get(0); // } // if (rp2_fl == null) { // rp2_fl = rp2_sl = rs.getFinishLayers().get(0); // } // // if (rp1_fl.equals(rp2_fl)) { // return rp1_fl; // } else if (rp1_fl.equals(rp2_sl)) { // return rp1_fl; // } else if (rp1_sl.equals(rp2_fl)) { // return rp1_sl; // } else if (rp1_sl.equals(rp2_sl)) { // return rp1_sl; // } // return null; // } /** * Return whether one of the tupels is the start point of the routing segment. * @param rs RoutingSegment * @param edgePoints List of tupels * @return edgePoints contains start of rs */ private static boolean containsStart(RoutingSegment rs, List<Tupel> edgePoints) { Tupel t1 = edgePoints.get(0); Tupel t2 = new Tupel(rs.getStartEnd().getLocation(), 0); if (t1.isEqualPosition(t2)) { return true; } return false; } // private static boolean containsStartReversed(RoutingSegment rs, List<Tupel> edgePoints) { // Tupel t1 = edgePoints.get(edgePoints.size() - 1); // Tupel t2 = new Tupel(rs.getStartEnd().getLocation(), 0); // if (t1.isEqualPosition(t2)) { // return true; // } // return false; // } /** * Return whether one of the tupels is the end point of the routing segment. * @param rs RoutingSegment * @param edgePoints List of tupels * @return edgePoints contains end of rs */ private static boolean containsEnd(RoutingSegment rs, List<Tupel> edgePoints) { Tupel t1 = edgePoints.get(edgePoints.size() - 1); Tupel t2 = new Tupel(rs.getFinishEnd().getLocation(), 0); if (t1.isEqualPosition(t2)) { return true; } return false; } /** * this method is used for multiterminal routing (not yet functional) * @param rs * @param edgePoints * @return */ private static boolean containsEndReversed(RoutingSegment rs, List<Tupel> edgePoints) { Tupel t1 = edgePoints.get(0); Tupel t2 = new Tupel(rs.getFinishEnd().getLocation(), 0); if (t1.isEqualPosition(t2)) { return true; } return false; } /** * Place a pin at the location of the tupel. * @param layerID Layer on which pin is placed * @param t tupel that represents the location * @return RoutePoint at the location of the pin */ private static RoutePoint placePin(int layerID, Tupel t) { RoutingLayer layer = getRoutingLayerByTupelLayer(layerID); if (DEBUG){ System.out.println("WIRING: Erstelle Pin auf [" + t.getX_InsideElectric() + ", " + t.getY_InsideElectric() + "]"); } return new RoutePoint(layer.getPin(), new Point2D.Double(t.getX_InsideElectric(), t.getY_InsideElectric()), 0); } /** * Place a pin at the given location * @param layer Layer on which pin is placed * @param x x coordinate * @param y y coordinate * @return RoutePoint at the location of the pin */ private static RoutePoint placeContact(RoutingLayer layer,double x, double y){ if (DEBUG){ System.out.println("WIRING: Erstelle Pin auf [" + x + ", " + y + "]"); } return new RoutePoint(layer.getPin(), new Point2D.Double(x, y), 0); } /** * Place a via at the given location * @param layer1 first layer connected to the via * @param layer2 second layer connected to the via * @param x x coordinate * @param y y coordinate * @return RoutePoint at the location of the via */ private static RoutePoint placeVia(int layer1, int layer2, int x, int y) { RoutingLayer startLayer = getRoutingLayerByTupelLayer(layer1); RoutingLayer finishLayer = getRoutingLayerByTupelLayer(layer2); if (DEBUG) { System.out.println("WIRING: Erstelle Via auf [" + x + ", " + y + "];"+startLayer.getName()+"<->"+finishLayer.getName()); } RoutingContact viaContact = getVia(startLayer, finishLayer); if (viaContact == null && DEBUG) { System.out.println("ERROR: via contact is null. Startlayer: " + startLayer.getMetalNumber() + ", Finishlayer: " + finishLayer.getMetalNumber()); } return new RoutePoint(viaContact, new Point2D.Double(x, y), 0); } /** * Calculate via RoutingContact that connects two layers. * @param l1 first layer * @param l2 second layer * @return RoutingContact via or null if impossible (the layers are not neighboured) */ private static 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; } /** * Get RoutingLayer object by id saved with a tupel * @param layer Layer id * @return RoutingLayer object */ private static RoutingLayer getRoutingLayerByTupelLayer(int layer) { return allLayers.get(metalLayerMap.get("Metal-" + (layer + 1))); } /** * Return whether tupel t2 can be reached from tupel t1 by changing the x coordinate or the y coorinate * @see WorkerThread.X_DIRECTION * @param t1 first tupel * @param t2 second tupel * @return direction */ private static boolean getWireDirection(Tupel t1, Tupel t2) { if (t1.getX_InsideRoutingArray() == t2.getX_InsideRoutingArray()) { return WorkerThread.Y_DIRECTION; } else { return WorkerThread.X_DIRECTION; } } /** * this method is used for multiterminal routing (not yet functional) * for now it will always call connect * @param rp * @param edgePoints * @param reversed */ public static void connect(RoutingPart rp, List<Tupel> edgePoints, boolean reversed) { if(reversed){ //algorithm for multiterminal wiring connectMultiterminal(rp,edgePoints); }else{ //standard algorithm connect(rp,edgePoints); } } /** * this method is used for multiterminal routing (not yet functional) * @param rp * @param edgePoints */ private static void connectMultiterminal(RoutingPart rp, List<Tupel> edgePoints) { boolean makeAngularWiresRectengular = true; LinkedList<WiringPart> contacts = new LinkedList<WiringPart>(); boolean lastContactWasVia = false; RoutePoint rp1 = rp.getEndRoutePoint(); boolean firstPoint = true; if(containsEndReversed(rp.rs, edgePoints)){ firstPoint=false; } Tupel t1; Tupel t2; int i=0; t1 = edgePoints.get(i); t2 = edgePoints.get(i + 1); //first point is rounded end point if (makeAngularWiresRectengular && containsEndReversed(rp.rs, edgePoints)) { boolean penultimateWireDirection = getWireDirection(t1, t2); RoutePoint rp2=null; if (penultimateWireDirection == WorkerThread.X_DIRECTION) { //we have to correct the second point of the routingpart so, that is at the same x-coordinate rp2=placeContact(rp.rs.getFinishLayers().get(0), rp1.getLocation().getX(),t1.getY_InsideElectric()); } if (penultimateWireDirection == WorkerThread.Y_DIRECTION) { //we have to replace the last point so, that it has the same y-coordinate rp2=placeContact(rp.rs.getFinishLayers().get(0),t1.getX_InsideElectric(), rp1.getLocation().getY()); } if(DEBUG) if(rp2==null) System.out.println("RP2 ist null"); contacts.add(new WiringPart(rp.rs.getFinishLayers().get(0), rp1, rp2, firstPoint, false)); firstPoint=true; rp1=rp2; } for (i=1; i < edgePoints.size()-1; i++) { t1 = edgePoints.get(i); t2 = edgePoints.get(i + 1); if (t1.isEqualPosition(t1) && (t1.getLayer() != t2.getLayer())) { //this is a via RoutePoint rp2 = placeVia(t1.getLayer(), t2.getLayer(), t1.getX_InsideElectric(), t1.getY_InsideElectric()); contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t1.getLayer()), rp1, rp2, firstPoint, false)); lastContactWasVia = true; rp1 = rp2; } else { if (!lastContactWasVia) { RoutePoint rp2 = placePin(t1.getLayer(), t1); contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t1.getLayer()), rp1, rp2, firstPoint, false)); lastContactWasVia = false; rp1 = rp2; } } firstPoint = true; } t2=edgePoints.get(edgePoints.size()-1); RoutePoint rp2 = placePin(t2.getLayer(), t2); boolean lastPoint=false; contacts.add(new WiringPart(getRoutingLayerByTupelLayer(t2.getLayer()), rp1, rp2, firstPoint, lastPoint)); wireRoutePoints(contacts, rp.rs); } } /** * This class represents a part of a wire lying on one layer. * @author Andy * */ class WiringPart { RoutingLayer layer; RoutePoint start, end; boolean isAlreadyWired_start, isAlreadyWired_end; //remember whether addWireEnd has already been called for this RoutePoint public WiringPart(RoutingLayer layer, RoutePoint start, RoutePoint end, boolean isAlreadyWiredStart, boolean isAlreadyWiredEnd) { this.layer = layer; this.start = start; this.end = end; isAlreadyWired_start = isAlreadyWiredStart; isAlreadyWired_end = isAlreadyWiredEnd; } /** * Get layer of this WiringPart * @return layer */ public RoutingLayer getLayer() { return layer; } /** * Get start of this WiringPart * @return start */ public RoutePoint getStart() { return start; } /** * Get end of this WiringPart * @return end */ public RoutePoint getEnd() { return end; } /** * Determine whether starting end has already been wired * @return */ public boolean isAlreadyWired_start() { return isAlreadyWired_start; } /** * Determine whether ending end has already been wired * @return */ public boolean isAlreadyWired_end() { return isAlreadyWired_end; } public String toString(){ return start.getLocation().toString()+"->"+end.getLocation().toString(); } }