/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Channel.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.generator.flag.router;
import java.util.ArrayList;
import java.util.List;
import com.sun.electric.tool.generator.flag.Utils;
import com.sun.electric.tool.Job;
/** rectangular region for routing */
public class Channel implements Comparable<Channel> {
// A channel may be adjacent to a wide power or ground strap.
// More spacing is required for wide metal.
private static final double METAL_WIDE_SPACE = 4;
private static final double METAL_SPACE = 3;
private static final double METAL_WIDTH = 3;
private static final double METAL_PITCH = METAL_SPACE + METAL_WIDTH;
private final boolean horizontal;
private final List<Track> tracks = new ArrayList<Track>();
private final double minL, maxL, // dimensions along channel length
minW, maxW; // dimensions along channel width
private final String description;
private static void prln(String msg) {Utils.prln(msg);}
public Channel(boolean horizontal, double l1, double l2,
double w1, double w2,
String description) {
this.horizontal = horizontal;
this.minL = Math.min(l1, l2);
this.maxL = Math.max(l1, l2);
this.minW = Math.min(w1, w2);
this.maxW = Math.max(w1, w2);
this.description = description;
double trackCent=minW+METAL_WIDE_SPACE+METAL_WIDTH/2;
while (trackCent+METAL_WIDTH/2 + METAL_WIDE_SPACE <=maxW) {
int ndx = tracks.size();
tracks.add(new Track(trackCent, this, ndx));
trackCent += METAL_SPACE + METAL_WIDTH;
}
}
public int compareTo(Channel c) {
double delta = minW - c.minW;
return (int) Math.signum(delta);
}
/** Find an unused part of a track that can connect xy1 with xy2.
* Any track whose center lies outside the bounds boundXY1 and boundXY2
* increases the manhatten distance of the route.
* If we need to select from two tracks that both minimize the
* manhatten distance, then choose the track closest to the center
* of the channel. This will tend to pack the segments into the
* smallest number of channels. */
public Segment allocate(double xy1, double xy2,
double boundXY1, double boundXY2) {
double min = Math.min(xy1, xy2) - METAL_PITCH;
double max = Math.max(xy1, xy2) + METAL_PITCH;
double minBound = Math.min(boundXY1, boundXY2);
double maxBound = Math.max(boundXY1, boundXY2);
// Check if span is outside this Channel
if (max>this.maxL || min<this.minL) return null;
// Try a greedy track allocation
double minCost = Double.MAX_VALUE;
Track bestTrack = null;
int nbTracks = tracks.size();
int midNdx = (nbTracks-1) / 2;
for (Track t : tracks) {
if (t.isAvailable(min, max)) {
double center = t.getCenter();
double cost = Math.abs(t.getIndex()-midNdx);
double c = center - maxBound;
if (c>0) cost+=c*1000;
c = minBound-center;
if (c>0) cost+=c*1000;
if (cost<minCost) {
minCost = cost;
bestTrack = t;
}
}
}
if (bestTrack==null) {
String lDesc = isHorizontal() ? "x=" : "y=";
String wDesc = isHorizontal() ? "y=" : "x=";
prln("Failed to allocate "+description+" segment from "+
lDesc+min+" to "+lDesc+max+" between "+wDesc+minW+" and "+
wDesc+maxW);
prln(this.toString());
return null;
}
Segment s = bestTrack.allocate(min, max);
Job.error(s==null,
"Impossible: we already checked it's available");
return s;
}
/** Metal-2 only PortInst don't allow us to chose the track center.
* Allocate the largest segment in the interval [min, max] that covers src */
public Segment allocateBiggestFromTrack(double min, double src, double max,
double trackCenter) {
for (Track t : tracks) {
double center = t.getCenter();
if (center==trackCenter) {
return t.allocateBiggest(min, src, max);
}
}
return null;
}
public boolean isHorizontal() {return horizontal;}
public boolean hasTracks() {return tracks.size()!=0;}
public String toString() {
double xMin, xMax, yMin, yMax;
if (horizontal) {
xMin=minL; yMin=minW;
xMax=maxL; yMax =maxW;
} else {
xMin=minW; yMin=minL;
xMax=maxW; yMax=maxL;
}
StringBuffer sb = new StringBuffer();
sb.append(horizontal ? " Horizontal" : " Vertical");
sb.append(" channel bounds: (");
sb.append(xMin+", "+yMin+") (");
sb.append(xMax+", "+yMax+") ");
sb.append(" Tracks:\n");
for (Track t : tracks) sb.append(t.toString());
return sb.toString();
}
// public double getMinX() {return isHorizontal() ? minL : minW;}
// public double getMaxX() {return isHorizontal() ? maxL : maxW;}
// public double getMinY() {return isHorizontal() ? minW : minL;}
// public double getMaxY() {return isHorizontal() ? maxW : maxL;}
public double getMinTrackCenter() {
return tracks.get(0).getCenter();
}
public double getMaxTrackCenter() {
return tracks.get(tracks.size()-1).getCenter();
}
public double getMinTrackEnd() {return minL;}
public double getMaxTrackEnd() {return maxL;}
}