/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: RoutingFrameLeeMoore.java * Written by: Alexander Herzog, Martin Fietz (Team 4) * * 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.experimentalLeeMoore2; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.tool.routing.experimentalLeeMoore2.GlobalRouterV3.RegionToRoute; import com.sun.electric.tool.routing.experimentalLeeMoore2.GlobalRouterV3.RouteToStitch; /** * Acts as interface betweed electric and our routing algorithm. Here our * algorithm specific classes are defined and conversions are done. * * @author Alexander Herzog, Martin Fietz * */ public class RoutingFrameLeeMoore extends BenchmarkRouter { final static boolean IS_DEBUG = false; public String getAlgorithmName() { return "Lee/Moore - 2"; } /** number of threads */ private RoutingLayer[] metalLayers; List<RoutingContact> allContacts; public static class Coordinate { double x; double y; int layer; ManhattenAlignment alignment = ManhattenAlignment.ma_undefined; public Coordinate(double x, double y, int z, ManhattenAlignment alignment) { this.x = x; this.y = y; this.layer = z; this.alignment = alignment; } public Coordinate(double x, double y, int z) { this.x = x; this.y = y; this.layer = z; } public Point2D getLocation() { return new Point2D.Double(x, y); } public int getLayer() { return layer; } } enum ManhattenAlignment { ma_horizontal, ma_vertical, ma_undefined } class RoutingIterationAnalysis{ int iteration; long global_ns; long detailed_ns; int wires_routed; } /** converts data, starts routing and then reconverts data */ protected void runRouting(Cell cell, List<RoutingSegment> segmentsToRoute, List<RoutingLayer> allLayers, List<RoutingContact> allContacts, List<RoutingGeometry> blockages) { this.allContacts = allContacts; long startTime = System.currentTimeMillis(); int numMetalLayers = 0; for (RoutingLayer rl : allLayers) if (rl.isMetal()) numMetalLayers++; metalLayers = new RoutingLayer[numMetalLayers + 1]; for (RoutingLayer rl : allLayers) if (rl.isMetal()) metalLayers[rl.getMetalNumber()] = rl; /** global router */ double minWidth = Double.MIN_VALUE; for (RoutingLayer lay : metalLayers) { if (lay != null) { minWidth = Math.max(lay.getMinWidth(), minWidth); } } double wireSpacing = Double.MIN_VALUE; for (RoutingLayer lay : metalLayers) { if (null == lay) { continue; } wireSpacing = Math.max(lay.getMinSpacing(lay), wireSpacing); } double maxSurr = Double.MIN_VALUE; for(RoutingLayer lay : metalLayers){ if(lay != null){ maxSurr = Math.max(lay.getMaxSurround(), maxSurr); } } double tileSize = maxSurr + minWidth; List<Integer> unrouted = null; Collection<RouteToStitch> routes = new ArrayList<RouteToStitch>(); GlobalRouterV3 global_router = null; DetailedRouter dr = null; long timeLeft = 0; int lastUnroutedSize = segmentsToRoute.size(); int noProgress = 0; do { if (global_router == null) { int num_regions = (int)Math.ceil(Math.sqrt(numThreads.getIntValue())); num_regions = num_regions <= 1 ? 2 : num_regions; global_router = new GlobalRouterV3(cell.getBounds(), num_regions, segmentsToRoute, numThreads.getIntValue(), tileSize); } else { global_router.Reinitialize(unrouted); } global_router.StartGlobalRouting(); Collection<RouteToStitch> cur_routes = global_router.output_coarse_routes .values(); RegionToRoute[] regions = global_router.output_regions; // debug("GlobalRouter created " + cur_routes.size() + " routes"); // adjustLayers(cur_routes, tileSize); /* detailed router */ if (dr == null) { dr = new DetailedRouter(numThreads.getIntValue(), metalLayers, regions, tileSize, enableOutput.getBooleanValue()); } dr.setRegions(regions); timeLeft = maxRuntime.getIntValue() - (System.currentTimeMillis() - startTime) / 1000; dr.setTimeout(timeLeft); dr.start(); dr.writeSolution(); unrouted = dr.getUnroutables(); /* remove unrouted routes and add them to the final routes */ Iterator<RouteToStitch> it = cur_routes.iterator(); while (it.hasNext()) { RouteToStitch single_route = it.next(); if (!unrouted.contains(single_route.id)) { /* assert that routes does not contain this route already */ // for (RouteToStitch rts : routes) { // assert (rts.id != single_route.id); // } /* add to route */ routes.add(single_route); } } timeLeft = maxRuntime.getIntValue() - (System.currentTimeMillis() - startTime) / 1000; if( global_router.wiried_routes.size() == lastUnroutedSize ) { noProgress +=1; } else { noProgress = 0; } lastUnroutedSize = global_router.wiried_routes.size(); } while ( unrouted.size() > 0 && timeLeft > 0 && noProgress <= 10 ); // writeAnalysis(process_analysis); /** stitch lists together */ // debug("Stitching Routes..."); Iterator<RouteToStitch> routes_it = routes.iterator(); while (routes_it.hasNext()) { RouteToStitch to_stitch = routes_it.next(); Iterator<SegPart> ts_it = to_stitch.coarse_route.iterator(); List<Coordinate> stitched_list = new ArrayList<Coordinate>(); while (ts_it.hasNext()) { SegPart cur_patch = ts_it.next(); // if(!(skipped == null || skipped == cur_patch.segment_part.get(0))){ // /* if exception occurs, the last point of a segPart is not // the same as the first point of its successor */ // assert(skipped == null || skipped == cur_patch.segment_part.get(0)); // } Coordinate co; for (Iterator<Coordinate> i = cur_patch.segment_part.iterator(); i .hasNext();) { co = i.next(); if (i.hasNext() || !ts_it.hasNext()) { stitched_list.add(co); } } } global_router.Retransform(stitched_list); stitched_list = minimizeCoordinateRoute(stitched_list); correctStartEnd(stitched_list); //debugPrintCoordinateList(stitched_list); doWiring(to_stitch.seg_head_tail, stitched_list); } } private void correctStartEnd(List<Coordinate> route){ /** begin with start */ Coordinate start = route.get(0); Coordinate start_succ = route.get(1); Coordinate start_link = addCornerPoint(start, start_succ); route.add(1, start_link); /** now the same with end */ if(route.size() > 3){ Coordinate end = route.get(route.size() - 1); Coordinate end_prev = route.get(route.size() - 2); Coordinate end_link = addCornerPoint(end, end_prev); route.add(route.size() - 1, end_link); } } private Coordinate addCornerPoint(Coordinate precise, Coordinate non_precise){ // assert(precise.layer == non_precise.layer); Coordinate ret = new Coordinate(-1, -1, precise.layer); if(precise.layer % 2 == 0){ //even layer => vertical ret.x = non_precise.x; ret.y = precise.y; }else{ //odd layer => horizontal ret.x = precise.x; ret.y = non_precise.y; } return ret; } public void adjustLayers( Collection<RouteToStitch> routes, double tileSize ) { for( RouteToStitch rts : routes ) { int lastLayer = rts.coarse_route.get(0).segment_part.get(0).getLayer(); int finishLayer = rts.coarse_route.get(rts.coarse_route.size()-1).segment_part.get(1).getLayer(); Coordinate c; /* the finish coordinate and start coordinate of two consecutive segparts are the same reference, * so we only have to process them once */ for( int i=0; i<rts.coarse_route.size()-1; i++ ) { // don't adjust the finish coordinate of the last coarse_route SegPart sp = rts.coarse_route.get(i); assert(sp.segment_part.size() == 2); c = sp.segment_part.get(1); assert(rts.coarse_route.get(i + 1).segment_part.get(0).alignment == c.alignment); assert(rts.coarse_route.get(i + 1).segment_part.get(0) == c); assert(c.alignment != ManhattenAlignment.ma_undefined); if( ( c.alignment == ManhattenAlignment.ma_horizontal && c.layer%2 != 1) // horizontal is even, should be odd || ( c.alignment == ManhattenAlignment.ma_vertical && c.layer%2 != 0) ) { // vertical is odd, should be even incOrDecLayer( c, lastLayer, finishLayer ); lastLayer = c.getLayer(); } } } } /* increment or decrement coordinate layer randomly */ public void incOrDecLayer(Coordinate c, int lastLayer, int finishLayer) { int dz = (int) Math.signum(finishLayer - lastLayer); if (dz == 0) { dz = -1; } if (0 < c.layer+dz && c.layer+dz < metalLayers.length) { c.layer += dz; } else if (0 < c.layer-dz && c.layer-dz < metalLayers.length) { c.layer -= dz; } } // public static void printCoordinateList(List<Coordinate> cs) { // for (Coordinate c : cs) // printCoordinate(c); // System.out.println("."); // } // // public static void printCoordinate(Coordinate c) { // System.out.print("(" + c.x + "," + c.y + "," + c.layer + ") "); // } private void doWiring(RoutingSegment rs, List<Coordinate> coords) { RoutePoint rpStart = new RoutePoint(RoutingContact.STARTPOINT, coords .get(0).getLocation(), 0); rs.addWireEnd(rpStart); RoutePoint fromRP = rpStart; RoutingLayer fromLayer = metalLayers[coords.get(0).layer]; for (int i = 1; i < coords.size()-1; i++) { RoutingLayer toLayer = metalLayers[coords.get(i).getLayer()]; RoutingContact rc = getContact(coords, i); // assert(rc != null); RoutePoint toRP = new RoutePoint(rc, coords.get(i).getLocation(), 0); RouteWire rw = new RouteWire(toLayer, toRP, fromRP, toLayer.getMinWidth() ); if(fromLayer == toLayer || isVia( coords, i)) { rs.addWireEnd(toRP); rs.addWire( rw ); fromRP = toRP; } fromLayer = toLayer; } RoutePoint rpFinish = new RoutePoint(RoutingContact.FINISHPOINT, coords .get(coords.size()-1).getLocation(), 0); rs.addWireEnd(rpFinish); RoutingLayer layer = metalLayers[coords.get(coords.size() - 1) .getLayer()]; RouteWire rw = new RouteWire(layer, rpFinish, fromRP, layer .getMinWidth()); rs.addWire(rw); } private List<Coordinate> minimizeCoordinateRoute(final List<Coordinate> lc) { List<Coordinate> result = new ArrayList<Coordinate>(); result.add(lc.get(0)); for (int i = 1; i < lc.size() - 1; i++) { Coordinate pre = lc.get(i - 1); Coordinate c = lc.get(i); Coordinate succ = lc.get(i + 1); // not same layer? if ((pre.layer != c.layer) || (c.layer != succ.layer)) { result.add(c); } else { // not on a straight line? if ((Math.abs(pre.x - c.x) < 0.001 && Math.abs(c.x - succ.x) < 0.001) == false && (Math.abs(pre.y - c.y) < 0.001 && Math.abs(c.y - succ.y) < 0.001) == false) result.add(c); } } result.add(lc.get(lc.size() - 1)); return result; } public RoutingContact getVia(RoutingLayer l1, RoutingLayer l2) { // assert (l1 != null && l2 != null); for (RoutingContact rc : allContacts) { if ((rc.getFirstLayer().equals(l1) && rc.getSecondLayer() .equals(l2)) || (rc.getFirstLayer().equals(l2) && rc.getSecondLayer() .equals(l1))) return rc; } // debug("no via: " + l1.getMetalNumber() + " -> " + l2.getMetalNumber()); return null; } public RoutingContact getContact(List<Coordinate> coords, int i) { if( isVia( coords, i) ) { return getVia(metalLayers[coords.get(i).getLayer()], metalLayers[coords.get(i + 1).getLayer()]); } else { return metalLayers[coords.get(i).getLayer()].getPin(); } } public boolean isVia(List<Coordinate> coords, int i) { if (i < coords.size()-1 && (coords.get(i).getLayer() != coords.get(i + 1).getLayer())) { return true; } else { return false; } } // private void debug(String s) { // if (enableOutput.getBooleanValue()) { // System.out.print(s); // } // } // public void debugPrintCoordinateList(List<Coordinate> cs) { // for (Coordinate c : cs) // debugPrintCoordinate(c); // debug(".\n"); // } // // public void debugPrintCoordinate(Coordinate c) { // debug("(" + c.x + "," + c.y + "," + c.layer + ") "); // } // Diese Methode muss ueberschrieben werden um eine NullPointerException zu // verhindern // public List<RoutingParameter> getParameters() { // List<RoutingParameter> allParams = new ArrayList<RoutingParameter>(); // return allParams; // } }