/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: FillGeneratorTool.java
*
* Copyright (c) 2006 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.generator.layout.fill;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.Tool;
import com.sun.electric.tool.generator.layout.Gallery;
import com.sun.electric.tool.generator.layout.LayoutLib;
import com.sun.electric.tool.generator.layout.TechType;
import java.lang.reflect.Constructor;
import java.util.*;
abstract class MetalFloorplanBase extends Floorplan
{
/** width Vdd wires */ public double vddWidth;
/** width Gnd wires */ public double gndWidth;
MetalFloorplanBase(double cellWidth, double cellHeight, boolean horiz)
{
super(cellWidth, cellHeight, horiz);
vddWidth = gndWidth = 0;
}
}
// ------------------------------ MetalFloorplanFlex ------------------------------
// Similar to Metalfloor but number of power/gnd lines is determined by cell size
class MetalFloorplanFlex extends MetalFloorplanBase {
public final double minWidth, space, vddReserve, gndReserve;
MetalFloorplanFlex(double cellWidth, double cellHeight,
double vddReserve, double gndReserve, double space,
double vddW, double gndW,
boolean horiz)
{
super(cellWidth, cellHeight, horiz);
this.vddWidth = vddW; //27;
this.gndWidth = gndW; //20;
this.space = space;
this.vddReserve = vddReserve;
this.gndReserve = gndReserve;
minWidth = vddReserve + gndReserve + 2*space + 2*gndWidth + 2*vddWidth;
}
}
// ------------------------------ MetalFloorplan ------------------------------
// Floor plan:
//
// half of Gnd reserved
// gggggggggggggggggggg
// wide space
// vvvvvvvvvvvvvvvvvvvv
// Vdd reserved
// vvvvvvvvvvvvvvvvvvvv
// wide space
// gggggggggggggggggggg
// half of Gnd reserved
class MetalFloorplan extends MetalFloorplanBase {
/** no gap between Vdd wires */ public final boolean mergedVdd;
/** if horizontal then y coordinate of top Vdd wire
* if vertical then x coordinate of right Vdd wire */
public final double vddCenter;
/** if horizontal then y coordinate of top Gnd wire
* if vertical then x coordinate of right Gnd wire */
public final double gndCenter;
public final double coverage;
private double roundDownOneLambda(double x) {
return Math.floor(x);
}
// Round metal widths down to multiples of 1 lambda resolution.
// Then metal center can be on 1/2 lambda grid without problems.
MetalFloorplan(double cellWidth, double cellHeight,
double vddReserve, double gndReserve,
double space, boolean horiz) {
super(cellWidth, cellHeight, horiz);
mergedVdd = vddReserve==0;
double cellSpace = horiz ? cellHeight : cellWidth;
double metalSpace = cellSpace - 2*space - vddReserve - gndReserve;
// gnd is always in two pieces
gndWidth = roundDownOneLambda(metalSpace / 4);
gndCenter = cellSpace/2 - gndReserve/2 - gndWidth/2;
// vdd may be one or two pieces
if (mergedVdd) {
vddWidth = gndWidth*2;
vddCenter = 0;
} else {
vddWidth = gndWidth;
vddCenter = vddReserve/2 + vddWidth/2;
}
// compute coverage statistics
double cellArea = cellWidth * cellHeight;
double strapLength = horiz ? cellWidth : cellHeight;
double vddArea = (mergedVdd ? 1 : 2) * vddWidth * strapLength;
double gndArea = 2 * gndWidth * strapLength;
coverage = (vddArea + gndArea)/cellArea;
}
// Save this code in case I need to replicate LoCo FillCell exactly
// MetalFloorplan(double cellWidth, double cellHeight,
// double vddReserve, double gndReserve,
// double space, boolean horiz) {
// super(cellWidth, cellHeight, horiz);
// mergedVdd = vddReserve==0;
// double cellSpace = horiz ? cellHeight : cellWidth;
// if (mergedVdd) {
// double w = cellSpace/2 - space - vddReserve;
// vddWidth = roundDownOneLambda(w);
// vddCenter = 0;
// } else {
// double w = (cellSpace/2 - space - vddReserve) / 2;
// vddWidth = roundDownOneLambda(w);
// vddCenter = vddReserve/2 + vddWidth/2;
// }
// double vddEdge = vddCenter + vddWidth/2;
// double w = cellSpace/2 - vddEdge - space - gndReserve/2;
// gndWidth = roundDownOneLambda(w);
// gndCenter = vddEdge + space + gndWidth/2;
//
// // compute coverage statistics
// double cellArea = cellWidth * cellHeight;
// double strapLength = horiz ? cellWidth : cellHeight;
// double vddArea = (mergedVdd ? 1 : 2) * vddWidth * strapLength;
// double gndArea = 2 * gndWidth * strapLength;
// coverage = (vddArea + gndArea)/cellArea;
// }
}
// ------------------------------- ExportBars ---------------------------------
class ExportBar
{
PortInst[] ports = null;
Double center = null;
ExportBar(PortInst p1, PortInst p2, double c)
{
ports = new PortInst[2];
ports[0] = p1;
ports[1] = p2;
center = (c); // autoboxing
}
}
class MetalLayer extends VddGndStraps {
protected MetalFloorplanBase plan;
protected int layerNum;
protected PrimitiveNode pin;
protected ArcProto metal;
protected ArrayList<ExportBar> vddBars = new ArrayList<ExportBar>();
protected ArrayList<ExportBar> gndBars = new ArrayList<ExportBar>();
public boolean addExtraArc() { return true; }
private void buildGnd(Cell cell) {
double pinX, pinY;
MetalFloorplan plan = (MetalFloorplan)this.plan;
if (plan.horizontal) {
pinX = plan.cellWidth/2; // - plan.gndWidth/2;
pinY = plan.gndCenter;
} else {
pinX = plan.gndCenter;
pinY = plan.cellHeight/2; // - plan.gndWidth/2;
}
PortInst tl = LayoutLib.newNodeInst(pin, -pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst tr = LayoutLib.newNodeInst(pin, pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst bl = LayoutLib.newNodeInst(pin, -pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst br = LayoutLib.newNodeInst(pin, pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
if (plan.horizontal) {
G.noExtendArc(metal, plan.gndWidth, tl, tr);
G.noExtendArc(metal, plan.gndWidth, bl, br);
gndBars.add(new ExportBar(bl, br, -plan.gndCenter));
gndBars.add(new ExportBar(tl, tr, plan.gndCenter));
} else {
G.noExtendArc(metal, plan.gndWidth, bl, tl);
G.noExtendArc(metal, plan.gndWidth, br, tr);
gndBars.add(new ExportBar(bl, tl, -plan.gndCenter));
gndBars.add(new ExportBar(br, tr, plan.gndCenter));
}
}
private void buildVdd(Cell cell) {
double pinX, pinY;
MetalFloorplan plan = (MetalFloorplan)this.plan;
if (plan.horizontal) {
pinX = plan.cellWidth/2; // - plan.vddWidth/2;
pinY = plan.vddCenter;
} else {
pinX = plan.vddCenter;
pinY = plan.cellHeight/2; // - plan.vddWidth/2;
}
if (plan.mergedVdd) {
PortInst tr = LayoutLib.newNodeInst(pin, pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst bl = LayoutLib.newNodeInst(pin, -pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
G.noExtendArc(metal, plan.vddWidth, bl, tr);
vddBars.add(new ExportBar(bl, tr, plan.vddCenter));
} else {
PortInst tl = LayoutLib.newNodeInst(pin, -pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst tr = LayoutLib.newNodeInst(pin, pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst bl = LayoutLib.newNodeInst(pin, -pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst br = LayoutLib.newNodeInst(pin, pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
if (plan.horizontal) {
G.noExtendArc(metal, plan.vddWidth, tl, tr);
G.noExtendArc(metal, plan.vddWidth, bl, br);
vddBars.add(new ExportBar(bl, br, -plan.vddCenter));
vddBars.add(new ExportBar(tl, tr, plan.vddCenter));
} else {
G.noExtendArc(metal, plan.vddWidth, bl, tl);
G.noExtendArc(metal, plan.vddWidth, br, tr);
vddBars.add(new ExportBar(bl, tl, -plan.vddCenter));
vddBars.add(new ExportBar(br, tr, plan.vddCenter));
}
}
}
/** It has to be protected to be overwritten by sub classes */
protected void buildGndAndVdd(Cell cell)
{
buildGnd(cell);
buildVdd(cell);
}
public MetalLayer(TechType t, int layerNum, Floorplan plan, Cell cell)
{
super(t);
this.plan = (MetalFloorplanBase)plan;
this.layerNum = layerNum;
metal = METALS[layerNum];
pin = PINS[layerNum];
buildGndAndVdd(cell);
}
public boolean isHorizontal() {return plan.horizontal;}
public int numVdd() {return vddBars.size();}
public double getVddCenter(int n) {
return (vddBars.get(n).center); // autoboxing
}
public PortInst getVdd(int n, int pos)
{return vddBars.get(n).ports[pos];}
public double getVddWidth(int n) {return plan.vddWidth;}
public int numGnd() {return gndBars.size();}
public double getGndCenter(int n) {
return (gndBars.get(n).center); // autoboxing
}
public PortInst getGnd(int n, int pos) {return gndBars.get(n).ports[pos];}
public double getGndWidth(int n) {return (plan).gndWidth;}
public PrimitiveNode getPinType() {return pin;}
public ArcProto getMetalType() {return metal;}
public double getCellWidth() {return plan.cellWidth;}
public double getCellHeight() {return plan.cellHeight;}
public int getLayerNumber() {return layerNum;}
}
// ------------------------------- MetalLayerFlex -----------------------------
class MetalLayerFlex extends MetalLayer {
public MetalLayerFlex(TechType t, int layerNum, Floorplan plan, Cell cell) {
super(t, layerNum, plan, cell);
}
public boolean addExtraArc() { return false; } // For automatic fill generator no extra arcs are wanted.
protected void buildGndAndVdd(Cell cell) {
double pinX, pinY;
double limit = 0;
MetalFloorplanFlex plan = (MetalFloorplanFlex)this.plan;
if (plan.horizontal)
{
limit = plan.cellHeight/2;
}
else
{
limit = plan.cellWidth/2;
}
double position = 0;
int i = 0;
while (position < limit)
{
boolean even = (i%2==0);
double maxDelta = 0, pos = 0;
if (even)
{
maxDelta = plan.vddReserve/2 + plan.vddWidth;
pos = plan.vddReserve/2 + plan.vddWidth/2 + position;
}
else
{
maxDelta = plan.gndReserve/2 + plan.gndWidth;
pos = plan.gndReserve/2 + plan.gndWidth/2 + position;
}
if (position + maxDelta > limit) return; // border was reached
if (plan.horizontal)
{
pinY = pos;
pinX = plan.cellWidth/2;
}
else
{
pinX = pos;
pinY = plan.cellHeight/2;
}
// Vdd if even, gnd if odd
if (!even)
addBars(cell, pinX, pinY, plan.gndWidth, gndBars);
else
addBars(cell, pinX, pinY, plan.vddWidth, vddBars);
if (even)
{
maxDelta = plan.vddReserve/2 + plan.vddWidth + plan.space + plan.gndWidth;
pos = plan.vddReserve/2 + plan.vddWidth + plan.space + plan.gndWidth/2 + position;
}
else
{
maxDelta = plan.gndReserve/2 + plan.gndWidth + plan.space + plan.vddWidth;
pos = plan.gndReserve/2 + plan.gndWidth + plan.space + plan.vddWidth/2 + position;
}
if (position + maxDelta > limit) return; // border was reached
if (plan.horizontal)
pinY = pos;
else
pinX = pos;
// Gnd if even, vdd if odd
if (!even)
{
addBars(cell, pinX, pinY, plan.vddWidth, vddBars);
position = ((plan.horizontal)?pinY:pinX) + plan.vddWidth/2 + plan.vddReserve/2;
}
else
{
addBars(cell, pinX, pinY, plan.gndWidth, gndBars);
position = ((plan.horizontal)?pinY:pinX) + plan.gndWidth/2 + plan.gndReserve/2;
}
i++;
}
}
private void addBars(Cell cell, double pinX, double pinY, double width, ArrayList<ExportBar> bars)
{
PortInst tl = LayoutLib.newNodeInst(pin, -pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst tr = LayoutLib.newNodeInst(pin, pinX, pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst bl = LayoutLib.newNodeInst(pin, -pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
PortInst br = LayoutLib.newNodeInst(pin, pinX, -pinY, G.DEF_SIZE,
G.DEF_SIZE, 0, cell
).getOnlyPortInst();
double center = 0;
if (plan.horizontal) {
G.noExtendArc(metal, width, tl, tr);
G.noExtendArc(metal, width, bl, br);
center = pinY;
bars.add(new ExportBar(bl, br, -center));
bars.add(new ExportBar(tl, tr, center));
} else {
G.noExtendArc(metal, width, bl, tl);
G.noExtendArc(metal, width, br, tr);
center = pinX;
bars.add(new ExportBar(bl, tl, -center));
bars.add(new ExportBar(br, tr, center));
}
}
}
//---------------------------------- CapLayer ---------------------------------
class CapLayer extends VddGndStraps {
private CapCell capCell;
private NodeInst capCellInst;
private CapFloorplan plan;
public boolean addExtraArc() { return true; }
public CapLayer(TechType t, CapFloorplan plan, CapCell capCell, Cell cell)
{
super(t);
this.plan = plan;
this.capCell = capCell;
double angle = plan.horizontal ? 0 : 90;
if (capCell != null)
capCellInst = LayoutLib.newNodeInst(capCell.getCell(), 0, 0, G.DEF_SIZE,
G.DEF_SIZE, angle, cell);
}
public boolean isHorizontal() {return plan.horizontal;}
public int numVdd() {return (capCell != null) ? capCell.numVdd() : 0;}
public PortInst getVdd(int n, int pos) {
return capCellInst.findPortInst(FillCell.VDD_NAME+"_"+n);
}
public double getVddCenter(int n) {
EPoint center = getVdd(n, 0).getCenter();
return plan.horizontal ? center.getY() : center.getX();
}
public double getVddWidth(int n) {return capCell.getVddWidth();}
public int numGnd() {return (capCell != null) ? capCell.numGnd() : 0;}
public PortInst getGnd(int n, int pos) {
return capCellInst.findPortInst(FillCell.GND_NAME+"_"+n);
}
public double getGndCenter(int n) {
EPoint center = getGnd(n, 0).getCenter();
return plan.horizontal ? center.getY() : center.getX();
}
public double getGndWidth(int n) {return capCell.getGndWidth();}
public PrimitiveNode getPinType() {return tech.m1pin();}
public ArcProto getMetalType() {return tech.m1();}
public double getCellWidth() {return plan.cellWidth;}
public double getCellHeight() {return plan.cellHeight;}
public int getLayerNumber() {return 1;}
}
class FillRouter {
private HashMap<String,List<PortInst>> portMap = new HashMap<String,List<PortInst>>();
private TechType tech;
private String makeKey(PortInst pi) {
EPoint center = pi.getCenter();
String x = ""+center.getX(); // LayoutLib.roundCenterX(pi);
String y = ""+center.getY(); // LayoutLib.roundCenterY(pi);
return x+"x"+y;
}
// private boolean bothConnect(ArcProto a, PortProto pp1, PortProto pp2) {
// return pp1.connectsTo(a) && pp2.connectsTo(a);
// }
private ArcProto findCommonArc(PortInst p1, PortInst p2) {
ArcProto[] metals = {tech.m6(), tech.m5(), tech.m4(), tech.m3(), tech.m2(), tech.m1()};
PortProto pp1 = p1.getPortProto();
PortProto pp2 = p2.getPortProto();
for (int i=0; i<metals.length; i++) {
if (pp1.connectsTo(metals[i]) && pp2.connectsTo(metals[i])) {
return metals[i];
}
}
return null;
}
private void connectPorts(List<PortInst> ports) {
for (Iterator<PortInst> it=ports.iterator(); it.hasNext(); ) {
PortInst first = it.next();
double width = LayoutLib.widestWireWidth(first);
it.remove();
for (PortInst pi : ports) {
ArcProto a = findCommonArc(first, pi);
if (a!=null) LayoutLib.newArcInst(a, width, first, pi);
}
}
}
private FillRouter(TechType t, ArrayList<PortInst> ports)
{
tech = t;
for (PortInst pi : ports) {
String key = makeKey(pi);
List<PortInst> l = portMap.get(key);
if (l==null) {
l = new LinkedList<PortInst>();
portMap.put(key, l);
}
l.add(pi);
}
// to guarantee deterministic results
List<String> keys = new ArrayList<String>();
keys.addAll(portMap.keySet());
Collections.sort(keys);
for (String str : keys) {
connectPorts(portMap.get(str));
}
}
public static void connectCoincident(TechType t, ArrayList<PortInst> ports) {
new FillRouter(t, ports);
}
}
/**
* Object for building fill libraries
*/
public class FillGeneratorTool extends Tool {
public FillGenConfig config;
protected Library lib;
private boolean libInitialized;
public List<Cell> masters;
protected CapCell capCell;
protected Floorplan[] plans;
/** the fill generator tool. */ private static FillGeneratorTool tool = getTool();
// Depending on generator plugin available
public static FillGeneratorTool getTool()
{
if (tool != null) return tool;
FillGeneratorTool tool;
try
{
Class<?> extraClass = Class.forName("com.sun.electric.plugins.generator.FillCellTool");
Constructor instance = extraClass.getDeclaredConstructor(); // varags
Object obj = instance.newInstance(); // varargs;
tool = (FillGeneratorTool)obj;
} catch (Exception e)
{
if (Job.getDebug())
System.out.println("GNU Release can't find Fill Cell Generator plugin");
tool = new FillGeneratorTool();
}
return tool;
}
public FillGeneratorTool() {
super("Fill Generator");
}
public void setConfig(FillGenConfig config)
{
this.config = config;
this.libInitialized = false;
}
public enum Units {NONE, LAMBDA, TRACKS}
protected boolean getOrientation() {return plans[plans.length-1].horizontal;}
/** Reserve space in the middle of the Vdd and ground straps for signals.
* @param layer the layer number. This may be 2, 3, 4, 5, or 6. The layer
* number 1 is reserved to mean "capacitor between Vdd and ground".
* @param reserved space to reserve in the middle of the central
* strap in case of Vdd. The value 0 makes the Vdd strap one large strap instead of two smaller
* adjacent straps.
* Space to reserve between the ground strap of this
* cell and the ground strap of the adjacent fill cell. The value 0 means
* that these two ground straps should abut to form a single large strap
* instead of two smaller adjacent straps.
* */
private double reservedToLambda(int layer, double reserved, Units units) {
if (units==LAMBDA) return reserved;
double nbTracks = reserved;
if (nbTracks==0) return 0;
return config.getTechType().reservedToLambda(layer, nbTracks);
}
private Floorplan[] makeFloorplans(boolean metalFlex, boolean hierFlex) {
Job.error(config.width==Double.NaN,
"width hasn't been specified. use setWidth()");
Job.error(config.height==Double.NaN,
"height hasn't been specified. use setHeight()");
double w = config.width;
double h = config.height;
int numLayers = config.getTechType().getNumMetals() + 1; // one extra for the cap
double[] vddRes = new double[numLayers]; //{0,0,0,0,0,0,0};
double[] gndRes = new double[numLayers]; //{0,0,0,0,0,0,0};
double[] vddW = new double[numLayers]; //{0,0,0,0,0,0,0};
double[] gndW = new double[numLayers]; //{0,0,0,0,0,0,0};
// set given values
for (FillGenConfig.ReserveConfig c : config.reserves)
{
vddRes[c.layer] = reservedToLambda(c.layer, c.vddReserved, c.vddUnits);
gndRes[c.layer] = reservedToLambda(c.layer, c.gndReserved, c.gndUnits);
if (c.vddWUnits != Units.NONE)
vddW[c.layer] = reservedToLambda(c.layer, c.vddWidth, c.vddWUnits);
if (c.gndWUnits != Units.NONE)
gndW[c.layer] = reservedToLambda(c.layer, c.gndWidth, c.gndWUnits);
}
boolean evenHor = config.evenLayersHorizontal;
boolean alignedMetals = true;
double[] spacing = new double[numLayers];
for (int i = 0; i < numLayers; i++) spacing[i] = config.drcSpacingRule;
// {config.drcSpacingRule,config.drcSpacingRule,
// config.drcSpacingRule,config.drcSpacingRule,
// config.drcSpacingRule,config.drcSpacingRule,config.drcSpacingRule};
if (alignedMetals)
{
double maxVddRes = 0, maxGndRes = 0, maxSpacing = 0, maxVddW = 0, maxGndW = 0;
for (int i = 0; i < vddRes.length; i++)
{
boolean vddOK = false, gndOK = false;
if (vddRes[i] > 0)
{
vddOK = true;
if (maxVddRes < vddRes[i]) maxVddRes = vddRes[i];
}
if (gndRes[i] > 0)
{
gndOK = true;
if (maxGndRes < gndRes[i]) maxGndRes = gndRes[i];
}
if (gndOK || vddOK) // checking max spacing rule
{
if (maxSpacing < config.drcSpacingRule) maxSpacing = config.drcSpacingRule; //drcRules[i];
}
if (maxVddW < vddW[i])
maxVddW = vddW[i];
if (maxGndW < gndW[i])
maxGndW = gndW[i];
}
// correct the values
for (int i = 0; i < vddRes.length; i++)
{
vddRes[i] = maxVddRes;
gndRes[i] = maxGndRes;
spacing[i] = maxSpacing;
vddW[i] = maxVddW;
gndW[i] = maxGndW;
}
}
Floorplan[] thePlans = new Floorplan[numLayers];
// 0 is always null
thePlans[1] = new CapFloorplan(w, h, !evenHor);
if (metalFlex)
{
if (!hierFlex)
{
for (int i = 2; i < numLayers; i++)
{
boolean horiz = (i%2==0);
thePlans[i] = new MetalFloorplanFlex(w, h, vddRes[i], gndRes[i], spacing[i], vddW[i], gndW[i], horiz);
}
return thePlans;
}
w = config.width = config.minTileSizeX;
h = config.height = config.minTileSizeY;
}
for (int i = 2; i < numLayers; i++)
{
boolean horiz = (i%2==0);
thePlans[i] = new MetalFloorplan(w, h, vddRes[i], gndRes[i], spacing[i], horiz);
}
return thePlans;
}
private void printCoverage(Floorplan[] plans) {
for (int i=2; i<plans.length; i++) {
System.out.println("metal-"+i+" coverage: "+
((MetalFloorplan)plans[i]).coverage);
}
}
private static CapCell getCMOS90CapCell(Library lib, CapFloorplan plan)
{
CapCell c = null;
try
{
Class<?> cmos90Class = Class.forName("com.sun.electric.plugins.tsmc.fill90nm.CapCellCMOS90");
Constructor capCellC = cmos90Class.getDeclaredConstructor(Library.class, CapFloorplan.class); // varargs
Object cell = capCellC.newInstance(lib, plan);
c = (CapCell)cell;
} catch (Exception e)
{
assert(false); // runtime error
}
return c;
}
protected void initFillParameters(boolean metalFlex, boolean hierFlex) {
if (libInitialized) return;
Job.error(config.fillLibName==null, "no library specified. Use setFillLibrary()");
Job.error((config.width==Double.NaN || config.width<=0), "no width specified. Use setFillCellWidth()");
Job.error((config.height==Double.NaN || config.height<=0), "no height specified. Use setFillCellHeight()");
plans = makeFloorplans(metalFlex, hierFlex);
if (!metalFlex) printCoverage(plans);
lib = LayoutLib.openLibForWrite(config.fillLibName);
if (!metalFlex) // don't do transistors
{
if (config.is180Tech())
{
capCell = new CapCellMosis(lib, (CapFloorplan) plans[1], config.getTechType());
}
else
{
capCell = getCMOS90CapCell(lib, (CapFloorplan) plans[1]);
}
}
libInitialized = true;
}
private void makeTiledCells(Cell cell, Floorplan[] plans, Library lib,
int[] tiledSizes) {
if (tiledSizes==null) return;
for (int num : tiledSizes)
{
TiledCell.makeTiledCell(num, num, cell, plans, lib);
}
}
public static Cell makeFillCell(Library lib, Floorplan[] plans,
int botLayer, int topLayer, CapCell capCell,
TechType tech,
ExportConfig expCfg, boolean metalFlex, boolean hierFlex) {
FillCell fc = new FillCell(tech);
return fc.makeFillCell1(lib, plans, botLayer, topLayer, capCell,
expCfg, metalFlex, hierFlex);
}
/**
* Method to create standard set of tiled cells.
*/
private Cell standardMakeAndTileCell(Library lib, Floorplan[] plans, int lowLay,
int hiLay, CapCell capCell,
TechType tech,
ExportConfig expCfg,
int[] tiledSizes, boolean metalFlex)
{
Cell master = makeFillCell(lib, plans, lowLay, hiLay, capCell,
tech, expCfg, metalFlex, false);
masters = new ArrayList<Cell>();
masters.add(master);
makeTiledCells(master, plans, lib, tiledSizes);
return master;
}
public static final Units LAMBDA = Units.LAMBDA;
public static final Units TRACKS = Units.TRACKS;
//public static final PowerType POWER = PowerType.POWER;
//public static final PowerType VDD = PowerType.VDD;
public static final ExportConfig PERIMETER = ExportConfig.PERIMETER;
public static final ExportConfig PERIMETER_AND_INTERNAL = ExportConfig.PERIMETER_AND_INTERNAL;
/** Reserve space in the middle of the Vdd and ground straps for signals.
* @param layer the layer number. This may be 2, 3, 4, 5, or 6. The layer
* number 1 is reserved to mean "capacitor between Vdd and ground".
* @param vddReserved space to reserve in the middle of the central Vdd
* strap.
* The value 0 makes the Vdd strap one large strap instead of two smaller
* adjacent straps.
* @param vddUnits LAMBDA or TRACKS
* @param gndReserved space to reserve between the ground strap of this
* cell and the ground strap of the adjacent fill cell. The value 0 means
* that these two ground straps should abut to form a single large strap
* instead of two smaller adjacent straps.
* @param gndUnits LAMBDA or TRACKS
* param tiledSizes an array of sizes. The default value is null. The
* value null means don't generate anything. */
// public void reserveSpaceOnLayer(int layer,
// double vddReserved, Units vddUnits,
// double gndReserved, Units gndUnits) {
// LayoutLib.error(layer<2 || layer>6,
// "Bad layer. Layers must be between 2 and 6 inclusive: "+
// layer);
// this.vddReserved[layer] = reservedToLambda(layer, vddReserved, vddUnits);
// this.gndReserved[layer] = reservedToLambda(layer, gndReserved, gndUnits);
// }
/** Create a fill cell using the current library, fill cell width, fill cell
* height, layer orientation, and reserved spaces for each layer. Then
* generate larger fill cells by tiling that fill cell according to the
* current tiled cell sizes.
* @param loLayer the lower layer. This may be 1 through 6. Layer 1 means
* build a capacitor using MOS transistors between Vdd and ground.
* @param hiLayer the upper layer. This may be 2 through 6. Note that hiLayer
* must be >= loLayer.
* @param exportConfig may be PERIMETER in which case exports are
* placed along the perimeter of the cell for the top two layers. Otherwise
* exportConfig must be PERIMETER_AND_INTERNAL in which case exports are
* placed inside the perimeter of the cell for the bottom layer.
* @param tiledSizes Array specifying composite Cells we should build by
* concatonating fill cells. For example int[] {2, 4, 7} means we should
* */
public Cell standardMakeFillCell(int loLayer, int hiLayer,
TechType tech,
ExportConfig exportConfig,
int[] tiledSizes, boolean metalFlex) {
initFillParameters(metalFlex, false);
Job.error(loLayer<1, "loLayer must be >=1");
int maxNumMetals = config.getTechType().getNumMetals();
Job.error(hiLayer>maxNumMetals, "hiLayer must be <=" + maxNumMetals);
Job.error(loLayer>hiLayer, "loLayer must be <= hiLayer");
Cell cell = null;
cell = standardMakeAndTileCell(lib, plans, loLayer, hiLayer, capCell,
tech, exportConfig,
tiledSizes, metalFlex);
return cell;
}
public void makeGallery() {
Gallery.makeGallery(lib);
}
public void writeLibrary(int backupScheme) throws JobException {
LayoutLib.writeLibrary(lib, backupScheme);
}
public enum FillTypeEnum {INVALID,TEMPLATE,CELL}
}