/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: FillCell.java
*
* Copyright (c) 2006, 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.layout.fill;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.tool.generator.layout.LayoutLib;
import com.sun.electric.tool.generator.layout.TechType;
import com.sun.electric.tool.Job;
//---------------------------------- FillCell --------------------------------
public class FillCell {
public static final String VDD_NAME = "vdd";
public static final String GND_NAME = "gnd";
public static final PortCharacteristic VDD_CHARACTERISTIC =
PortCharacteristic.PWR;
public static final PortCharacteristic GND_CHARACTERISTIC =
PortCharacteristic.GND;
private int vddNum, gndNum;
private final TechType tech;
private String vddName() {
int n = vddNum++;
return VDD_NAME + (n==0 ? "" : ("_"+n));
}
private String gndName() {
int n = gndNum++;
return GND_NAME + (n==0 ? "" : ("_"+n));
}
public void exportPerimeter(VddGndStraps lay, Cell cell) {
for (int i=0; i<lay.numGnd(); i++) {
exportStripeEnds(i, lay, true, cell);
}
for (int i=0; i<lay.numVdd(); i++) {
exportStripeEnds(i, lay, false, cell);
}
}
public void exportPerimeter(VddGndStraps[] lays, int botLay, int topLay,
ExportConfig exptConfig, Cell cell) {
int[] perim = exptConfig.getPerimeterExports(botLay, topLay);
for (int i=0; i<perim.length; i++) {
VddGndStraps lay = lays[perim[i]];
if (lay!=null) exportPerimeter(lay, cell);
}
}
private void exportStripeEnds(int n, VddGndStraps lay,
boolean gnd, Cell cell) {
PrimitiveNode pin = lay.getPinType();
ArcProto metal = lay.getMetalType();
double edge = (lay.isHorizontal() ? lay.getCellWidth() : lay.getCellHeight())/2;
double center = gnd ? lay.getGndCenter(n) : lay.getVddCenter(n);
double width = gnd ? lay.getGndWidth(n) : lay.getVddWidth(n);
PortInst piLeft = gnd ? lay.getGnd(n, 0) : lay.getVdd(n, 0);
PortInst piRight = gnd ? lay.getGnd(n, 1) : lay.getVdd(n, 1);
if (lay.isHorizontal()) {
export(-edge, center, pin, metal, piLeft, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
export(edge, center, pin, metal, piRight, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
} else {
export(center, -edge, pin, metal, piLeft, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
export(center, edge, pin, metal, piRight, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
}
}
private void export(double x, double y, PrimitiveNode pin,
ArcProto metal, PortInst conn, double w,
String name, boolean gnd, Cell cell,
boolean withExtraArc)
{
Export e = null;
if (false) // withExtraArc)
{
PortInst pi = LayoutLib.newNodeInst(pin, x, y, G.DEF_SIZE, G.DEF_SIZE,
0, cell).getOnlyPortInst();
G.noExtendArc(metal, w, conn, pi);
e = Export.newInstance(cell, pi, name);
}
else
e = Export.newInstance(cell, conn, name);
e.setCharacteristic(gnd ? GND_CHARACTERISTIC :
VDD_CHARACTERISTIC);
}
public void exportWiring(VddGndStraps lay, Cell cell) {
for (int i=0; i<lay.numGnd(); i++) {
exportStripeCenter(i, lay, true, cell);
}
for (int i=0; i<lay.numVdd(); i++) {
exportStripeCenter(i, lay, false, cell);
}
}
public void exportWiring(VddGndStraps[] lays, int botLay, int topLay,
ExportConfig exptConfig, Cell cell) {
int[] intnl = exptConfig.getInternalExports(botLay, topLay);
for (int i=0; i<intnl.length; i++) {
VddGndStraps lay = lays[intnl[i]];
if (lay!=null) exportWiring(lay, cell);
}
}
private void exportStripeCenter(int n, VddGndStraps lay,
boolean gnd, Cell cell) {
PrimitiveNode pin = lay.getPinType();
ArcProto metal = lay.getMetalType();
double center = gnd ? lay.getGndCenter(n) : lay.getVddCenter(n);
double width = gnd ? lay.getGndWidth(n) : lay.getVddWidth(n);
PortInst pi = gnd ? lay.getGnd(n, 0) : lay.getVdd(n, 0); // Doesn't matter which bar end is taken
if (lay.isHorizontal()) {
export(0, center, pin, metal, pi, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
} else {
export(center, 0, pin, metal, pi, width,
gnd ? gndName() : vddName(), gnd, cell, lay.addExtraArc());
}
}
private void appendExportLayerNumbers(StringBuffer buf,
String type, int[] layerNbs) {
if (layerNbs.length>0) {
buf.append(type);
for (int i=0; i<layerNbs.length; i++) {
buf.append(layerNbs[i]);
}
}
}
private String fillName(int lo, int hi, ExportConfig expConfig) {
StringBuffer buf = new StringBuffer();
buf.append("fill");
if (lo!=1 || hi!=tech.getNumMetals()) {
for (int i=lo; i<=hi; i++) buf.append(i);
}
if (expConfig==ExportConfig.PERIMETER) {
// append nothing
} else if (expConfig==ExportConfig.PERIMETER_AND_INTERNAL) {
buf.append("w");
} else {
int[] perim = expConfig.getPerimeterExports(lo, hi);
appendExportLayerNumbers(buf, "p", perim);
int[] intnl = expConfig.getInternalExports(lo, hi);
appendExportLayerNumbers(buf, "w", intnl);
}
buf.append("{lay}");
return buf.toString();
}
private VddGndStraps[] findHoriVert(VddGndStraps lay1, VddGndStraps lay2) {
if (lay1.isHorizontal()) {
Job.error(lay2.isHorizontal(), "adjacent layers both horizontal");
return new VddGndStraps[] {lay1, lay2};
} else {
Job.error(!lay2.isHorizontal(), "adjacent layers both vertical");
return new VddGndStraps[] {lay2, lay1};
}
}
/** Move via's edge inside by 1 lambda if via's edge is on cell's edge */
private static class ViaDim {
public final double x, y, w, h;
public ViaDim(VddGndStraps lay, double x, double y, double w, double h) {
if (x+w/2 == lay.getCellWidth()/2) {
w -= 1;
x -= .5;
} else if (x-w/2 == -lay.getCellWidth()/2) {
w -= 1;
x += .5;
}
if (y+h/2 == lay.getCellHeight()/2) {
h -= 1;
y -= .5;
} else if (y-h/2 == -lay.getCellHeight()/2) {
h -= 1;
y += .5;
}
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
}
private void connectVddStraps(VddGndStraps horLay, int horNdx,
VddGndStraps verLay, int verNdx, Cell cell) {
double w = verLay.getVddWidth(verNdx);
double x = verLay.getVddCenter(verNdx);
ArcProto verMetal = verLay.getMetalType();
// Try to select the closest pin in the other layer , even to the left, odd to the right
PortInst verPort = (horNdx%2==0) ? verLay.getVdd(verNdx, 0) : verLay.getVdd(verNdx, 1);
double h = horLay.getVddWidth(horNdx);
double y = horLay.getVddCenter(horNdx);
ArcProto horMetal = horLay.getMetalType();
PrimitiveNode viaType = tech.getViaFor(verMetal, horMetal);
PortInst horPort = (verNdx%2==0) ? horLay.getVdd(horNdx, 0) : horLay.getVdd(horNdx, 1);
// Line below will detect mixture of technologies.
Job.error(viaType==null, "can't find via for metal layers " + verMetal + " " + horMetal);
ViaDim d = new ViaDim(horLay, x, y, w, h);
PortInst via = LayoutLib.newNodeInst(viaType, d.x, d.y, d.w, d.h, 0,
cell).getOnlyPortInst();
G.noExtendArc(horMetal, h, horPort, via);
G.noExtendArc(verMetal, w, via, verPort);
// LayoutLib.newArcInst(horMetal, G.DEF_SIZE, horPort, via);
// LayoutLib.newArcInst(verMetal, G.DEF_SIZE, via, verPort);
}
private void connectGndStraps(VddGndStraps horLay, int horNdx,
VddGndStraps verLay, int verNdx, Cell cell) {
double w = verLay.getGndWidth(verNdx);
double x = verLay.getGndCenter(verNdx);
ArcProto verMetal = verLay.getMetalType();
// Try to select the closest pin in the other layer , even to the left, odd to the right
PortInst verPort = (horNdx%2==0) ? verLay.getGnd(verNdx, 0) : verLay.getGnd(verNdx, 1);
double h = horLay.getGndWidth(horNdx);
double y = horLay.getGndCenter(horNdx);
ArcProto horMetal = horLay.getMetalType();
PrimitiveNode viaType = tech.getViaFor(verMetal, horMetal);
PortInst horPort = (verNdx%2==0) ? horLay.getGnd(horNdx, 0) : horLay.getGnd(horNdx, 1);
Job.error(viaType==null, "can't find via for metal layers");
ViaDim d = new ViaDim(horLay, x, y, w, h);
PortInst via = LayoutLib.newNodeInst(viaType, d.x, d.y, d.w, d.h, 0,
cell).getOnlyPortInst();
G.noExtendArc(horMetal, h, horPort, via);
G.noExtendArc(verMetal, w, via, verPort);
// LayoutLib.newArcInst(horMetal, G.DEF_SIZE, horPort, via);
// LayoutLib.newArcInst(verMetal, G.DEF_SIZE, via, verPort);
}
private void connectLayers(VddGndStraps loLayer, VddGndStraps hiLayer,
Cell cell) {
VddGndStraps layers[] = findHoriVert(loLayer, hiLayer);
VddGndStraps horLay = layers[0];
VddGndStraps verLay = layers[1];
for (int h=0; h<horLay.numVdd(); h++) {
for (int v=0; v<verLay.numVdd(); v++) {
connectVddStraps(horLay, h, verLay, v, cell);
}
}
for (int h=0; h<horLay.numGnd(); h++) {
for (int v=0; v<verLay.numGnd(); v++) {
connectGndStraps(horLay, h, verLay, v, cell);
}
}
}
protected Cell makeFillCell1(Library lib, Floorplan[] plans, int botLayer,
int topLayer, CapCell capCell,
ExportConfig expCfg,
boolean metalFlex, boolean hierFlex) {
String name = fillName(botLayer, topLayer, expCfg);
Cell cell = Cell.newInstance(lib, name);
VddGndStraps[] layers = new VddGndStraps[topLayer+1];
for (int i=topLayer; i>=botLayer; i--) {
if (i==1) {
layers[i] = new CapLayer(tech, (CapFloorplan) plans[i], capCell,
cell);
} else {
if (metalFlex && !hierFlex)
layers[i] = new MetalLayerFlex(tech, i, plans[i], cell);
else
layers[i] = new MetalLayer(tech, i, plans[i], cell);
}
if (i!=topLayer) {
// connect to upper level
connectLayers(layers[i], layers[i+1], cell);
}
}
exportPerimeter(layers, botLayer, topLayer, expCfg, cell);
exportWiring(layers, botLayer, topLayer, expCfg, cell);
double cellWidth = plans[topLayer].cellWidth;
double cellHeight = plans[topLayer].cellHeight;
LayoutLib.newNodeInst(tech.essentialBounds(),
-cellWidth/2, -cellHeight/2,
G.DEF_SIZE, G.DEF_SIZE, 180, cell);
LayoutLib.newNodeInst(tech.essentialBounds(),
cellWidth/2, cellHeight/2,
G.DEF_SIZE, G.DEF_SIZE, 0, cell);
// cell.setCharacteristicSpacing(cellWidth, cellHeight);
return cell;
}
protected FillCell(TechType tech) {
this.tech = tech;
}
}