/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: SeaOfGates.java * Routing tool: Sea of Gates control * Written by: Steven M. Rubin * * Copyright (c) 2007 Sun Microsystems and Static Free Software * * 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 com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.network.Network; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.TextUtils; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.variable.EditWindow_; import com.sun.electric.database.variable.UserInterface; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.Technology; import com.sun.electric.technology.technologies.Generic; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; /** * Class to control sea-of-gates routing. */ public class SeaOfGates { /** * Method to run Sea-of-Gates routing on the current cell. */ public static void seaOfGatesRoute() { // get cell and network information UserInterface ui = Job.getUserInterface(); Cell cell = ui.needCurrentCell(); if (cell == null) return; Netlist netList = cell.getNetlist(); if (netList == null) { System.out.println("Sorry, a deadlock aborted routing (network information unavailable). Please try again"); return; } // get list of selected nets Set<Network> nets = null; boolean didSelection = false; EditWindow_ wnd = ui.getCurrentEditWindow_(); if (wnd != null) { nets = wnd.getHighlightedNetworks(); if (nets.size() > 0) didSelection = true; } if (!didSelection) { nets = new HashSet<Network>(); for(Iterator<Network> it = netList.getNetworks(); it.hasNext(); ) nets.add(it.next()); } // only consider nets that have unrouted arcs on them Set<Network> netsToRoute = new TreeSet<Network>(new TextUtils.NetworksByName()); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != Generic.tech().unrouted_arc) continue; Network net = netList.getNetwork(ai, 0); if (nets.contains(net)) netsToRoute.add(net); } // make sure there is something to route if (netsToRoute.size() <= 0) { ui.showErrorMessage(didSelection ? "Must select one or more Unrouted Arcs" : "There are no Unrouted Arcs in this cell", "Routing Error"); return; } // Run seaOfGatesRoute on selected unrouted arcs seaOfGatesRoute(netList, netsToRoute, null); } /** * Method to run Sea-of-Gates routing on specified cell. * Presumes that it is inside of a Job. */ public static void seaOfGatesRoute(Cell cell, SeaOfGatesOptions prefs) { Netlist netList = cell.getNetlist(); Set<Network> netsToRoute = new TreeSet<Network>(new TextUtils.NetworksByName()); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != Generic.tech().unrouted_arc) continue; netsToRoute.add(netList.getNetwork(ai, 0)); } // Run seaOfGatesRoute on unrouted arcs seaOfGatesRoute(netList, netsToRoute, prefs); } /** * Method to run Sea-of-Gates routing */ private static void seaOfGatesRoute(Netlist netList, Set<Network> netsToRoute, SeaOfGatesOptions prefs) { // get cell from network information Cell cell = netList.getCell(); Map<Network,ArcInst[]> arcMap = null; if (cell.getView() != View.SCHEMATIC) arcMap = netList.getArcInstsByNetwork(); // order the nets appropriately List<NetsToRoute> orderedNetsToRoute = new ArrayList<NetsToRoute>(); for(Network net : netsToRoute) { if (net.getNetlist() != netList) throw new IllegalArgumentException("netList"); boolean isPwrGnd = false; for(Iterator<Export> it = net.getExports(); it.hasNext(); ) { Export e = it.next(); if (e.isGround() || e.isPower()) { isPwrGnd = true; break; } } double length = 0; ArcInst[] arcsOnNet = null; if (arcMap != null) arcsOnNet = arcMap.get(net); else { List<ArcInst> arcList = new ArrayList<ArcInst>(); for(Iterator<ArcInst> it = net.getArcs(); it.hasNext(); ) arcList.add(it.next()); arcsOnNet = arcList.toArray(new ArcInst[]{}); } for(ArcInst ai : arcsOnNet) { length += ai.getLambdaLength(); PortProto headPort = ai.getHeadPortInst().getPortProto(); PortProto tailPort = ai.getTailPortInst().getPortProto(); if (headPort.isGround() || headPort.isPower() || tailPort.isGround() || tailPort.isPower()) isPwrGnd = true; } NetsToRoute ntr = new NetsToRoute(net, length, isPwrGnd); orderedNetsToRoute.add(ntr); } Collections.sort(orderedNetsToRoute, new NetsToRouteByLength()); // convert to a list of Arcs to route because nets get redone after each one is routed List<ArcInst> arcsToRoute = new ArrayList<ArcInst>(); for(NetsToRoute ntr : orderedNetsToRoute) { ArcInst[] arcsOnNet = null; if (arcMap != null) arcsOnNet = arcMap.get(ntr.net); else { List<ArcInst> arcList = new ArrayList<ArcInst>(); for(Iterator<ArcInst> it = ntr.net.getArcs(); it.hasNext(); ) arcList.add(it.next()); arcsOnNet = arcList.toArray(new ArcInst[]{}); } for(ArcInst ai : arcsOnNet) { if (ai.getProto() != Generic.tech().unrouted_arc) continue; arcsToRoute.add(ai); break; } } if (prefs == null) { // do the routing in a separate job prefs = new SeaOfGatesOptions(); prefs.getOptionsFromPreferences(); new SeaOfGatesJob(cell, arcsToRoute, prefs); } else { SeaOfGatesEngine router = new SeaOfGatesEngine(); router.routeIt(Job.getRunningJob(), cell, arcsToRoute, prefs); } } /** * Class to define a network that needs to be routed. * Extra information lets the nets be sorted by length and power/ground usage. */ private static class NetsToRoute { private Network net; private double length; private boolean isPwrGnd; NetsToRoute(Network net, double length, boolean isPwrGnd) { this.net = net; this.length = length; this.isPwrGnd = isPwrGnd; } } /** * Comparator class for sorting NetsToRoute by their length and power/ground usage. */ public static class NetsToRouteByLength implements Comparator<NetsToRoute> { /** * Method to sort NetsToRoute by their length and power/ground usage. */ public int compare(NetsToRoute ntr1, NetsToRoute ntr2) { // make power or ground nets come first if (ntr1.isPwrGnd != ntr2.isPwrGnd) { if (ntr1.isPwrGnd) return -1; return 1; } // make shorter nets come before longer ones if (ntr1.length < ntr2.length) return -1; if (ntr1.length > ntr2.length) return 1; return 0; } } /** * Class to run sea-of-gates routing in a separate Job. */ private static class SeaOfGatesJob extends Job { private Cell cell; private int[] arcIdsToRoute; private SeaOfGatesOptions prefs; protected SeaOfGatesJob(Cell cell, List<ArcInst> arcsToRoute, SeaOfGatesOptions prefs) { super("Sea-Of-Gates Route", Routing.getRoutingTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.cell = cell; arcIdsToRoute = new int[arcsToRoute.size()]; for (int i = 0; i < arcsToRoute.size(); i++) arcIdsToRoute[i] = arcsToRoute.get(i).getArcId(); this.prefs = prefs; startJob(); } public boolean doIt() throws JobException { SeaOfGatesEngine router = new SeaOfGatesEngine(); List<ArcInst> arcsToRoute = new ArrayList<ArcInst>(); for (int arcId: arcIdsToRoute) arcsToRoute.add(cell.getArcById(arcId)); router.routeIt(this, cell, arcsToRoute, prefs); return true; } } /** * Class to hold preferences during Sea-of-Gates routing run. */ public static class SeaOfGatesOptions implements Serializable { public boolean useParallelFromToRoutes; public boolean useParallelRoutes; public double maxArcWidth; public int complexityLimit; private Map<Technology,Set<ArcProto>> preventUse; private Map<Technology,Set<ArcProto>> favor; public SeaOfGatesOptions() { useParallelFromToRoutes = true; useParallelRoutes = false; maxArcWidth = 10; complexityLimit = 200000; preventUse = new HashMap<Technology,Set<ArcProto>>(); favor = new HashMap<Technology,Set<ArcProto>>(); } public void getOptionsFromPreferences() { useParallelFromToRoutes = Routing.isSeaOfGatesUseParallelFromToRoutes(); useParallelRoutes = Routing.isSeaOfGatesUseParallelRoutes(); maxArcWidth = Routing.getSeaOfGatesMaxWidth(); complexityLimit = Routing.getSeaOfGatesComplexityLimit(); for(Iterator<Technology> it = Technology.getTechnologies(); it.hasNext(); ) { Technology tech = it.next(); for(Iterator<ArcProto> aIt = tech.getArcs(); aIt.hasNext(); ) { ArcProto ap = aIt.next(); if (Routing.isSeaOfGatesFavor(ap)) { Set<ArcProto> arcNames = favor.get(tech); if (arcNames == null) favor.put(tech, arcNames = new HashSet<ArcProto>()); arcNames.add(ap); } if (Routing.isSeaOfGatesPrevent(ap)) { Set<ArcProto> arcNames = preventUse.get(tech); if (arcNames == null) preventUse.put(tech, arcNames = new HashSet<ArcProto>()); arcNames.add(ap); } } } } public boolean isPrevented(ArcProto ap) { Set<ArcProto> prefPrevent = preventUse.get(ap.getTechnology()); if (prefPrevent != null && prefPrevent.contains(ap)) return true; return false; } public boolean isFavored(ArcProto ap) { Set<ArcProto> prefFavorites = favor.get(ap.getTechnology()); if (prefFavorites != null && prefFavorites.contains(ap)) return true; return false; } } }