/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Decode.java
* MOSIS CMOS PLA Generator.
* Originally written by Wallace Kroeker at the University of Calgary
* Translated to Java by Steven Rubin, Sun Microsystems.
*
* Copyright (c) 2005 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.cmosPLA;
import com.sun.electric.database.geometry.Orientation;
import com.sun.electric.database.geometry.Poly;
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.PortProto;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.variable.Variable;
import java.awt.geom.Rectangle2D;
/**
* Class to generate the decoder part of MOSIS CMOS PLAs.
*/
public class Decode
{
private PLA pla;
Decode(PLA pla)
{
this.pla = pla;
}
Cell decodeGen(Library library, Cell pmosCell, Cell nmosCell, String cellName, boolean inputsOnTop)
{
Cell cell = Cell.makeInstance(library, cellName);
NodeInst pNode = pla.makeInstance(cell, pmosCell, 0, 0, false);
if (pNode == null) return null;
pNode.rotate(Orientation.RRR); // rotate by 90 degrees
Rectangle2D nodeRect = pNode.getBounds();
double x = nodeRect.getWidth();
if (x < 0) x = -x;
x += 12; // SEPARATION
NodeInst nNode = pla.makeInstance(cell, nmosCell, x, 0, false);
if (nNode == null) return null;
nNode.rotate(Orientation.RRR); // rotate by 90 degrees
NodeInst [] both = decodeBufs(pmosCell, pNode, nmosCell, nNode, cell, x, inputsOnTop);
if (both == null) return null;
if (decodeRoute(pmosCell, pNode, nmosCell, nNode, cell, both[0], both[1], inputsOnTop)) return null;
decExp(nmosCell, nNode, cell);
return cell;
}
private NodeInst [] decodeBufs(Cell pmosCell, NodeInst pNode, Cell nmosCell,
NodeInst nNode, Cell decodeCell, double X, boolean inputsOnTop)
{
NodeInst lastNode = null;
NodeInst newNode = null;
NodeInst firstPNode = null, lastPNode = null, lastNNode = null;
int rows = 2;
Variable var = pmosCell.getVar("PLA_access_rows");
if (var != null) rows = ((Integer)var.getObject()).intValue(); else
System.out.println("ACCESS_rows defaulting to 2");
Export pwrWPort = null, pwrEPort = null, gndWPort = null, gndEPort = null;
char side = 'w';
if (inputsOnTop) side = 'e';
Rectangle2D nodeBounds = pNode.getBounds();
double lowX = nodeBounds.getMinX();
double lowY = nodeBounds.getMinY();
double highY = nodeBounds.getMaxY();
Rectangle2D bufBounds = pla.decoderInv.getBounds();
double diff = bufBounds.getHeight();
if (diff < 0) diff = -diff;
int limit = rows / 4;
if (limit == 0 || (rows % 4) != 0) limit++;
int cnt = 0;
double y = highY;
if (inputsOnTop) y = lowY - diff;
y -= 13;
double xOffset = lowX - 38;
if ((rows %4) == 0) xOffset = lowX - 18;
pwrWPort = pla.decoderInv.findExport("PWR.m-2.w");
pwrEPort = pla.decoderInv.findExport("PWR.m-2.e");
gndWPort = pla.decoderInv.findExport("GND.m-2.w");
gndEPort = pla.decoderInv.findExport("GND.m-2.e");
for (int i = limit; i > 0; i--)
{
newNode = pla.makeInstance(decodeCell, pla.decoderInv, i*50 + xOffset, y, !inputsOnTop);
if (newNode == null) return(null);
NodeInst newNode2 = pla.makeInstance(decodeCell, pla.decoderInv, X + i*50 + xOffset, y, !inputsOnTop);
if (newNode2 == null) return(null);
if (lastPNode == null && lastNNode == null)
{
Export.newInstance(decodeCell, newNode2.findPortInstFromProto(pwrEPort), "PWR.m-2.e");
Export.newInstance(decodeCell, newNode2.findPortInstFromProto(gndEPort), "GND.m-2.e");
firstPNode = lastPNode = newNode;
lastNNode = lastNode = newNode2;
} else
{
// get wired
if (pwrWPort != null && pwrEPort != null)
{
pla.makeWire(pla.m2Arc, 14, lastPNode, pwrWPort, newNode, pwrEPort, decodeCell);
pla.makeWire(pla.m2Arc, 14, lastNNode, pwrWPort, newNode2, pwrEPort, decodeCell);
}
if (gndWPort != null && gndEPort != null)
{
pla.makeWire(pla.m2Arc, 14, lastNNode, gndWPort, newNode, gndEPort, decodeCell);
pla.makeWire(pla.m2Arc, 14, lastNNode, gndWPort, newNode2, gndEPort, decodeCell);
}
lastPNode = newNode;
lastNNode = newNode2;
}
for (int x = cnt; x < cnt+4; x++)
{
String aName = "ACCESS" + x + ".m-1." + side;
Export pPort = pmosCell.findExport(aName);
Export nPort = pla.decoderInv.findExport("LINE" + (x % 4) + ".p.n");
if (pPort != null && nPort != null)
pla.makeWire(pla.pArc, 2, pNode, pPort, newNode, nPort, decodeCell);
pPort = nmosCell.findExport(aName);
if (nPort != null && pPort != null)
pla.makeWire(pla.pArc, 2, nNode, pPort, newNode2, nPort, decodeCell);
}
cnt += 4;
}
if (pwrWPort != null && pwrEPort != null)
{
pla.makeWire(pla.m2Arc, 14, lastNNode, pwrWPort, firstPNode, pwrEPort, decodeCell);
Export.newInstance(decodeCell, lastPNode.findPortInstFromProto(pwrWPort), "PWR.m-2.w");
}
if (gndWPort != null && gndEPort != null)
{
pla.makeWire(pla.m2Arc, 14, lastNNode, gndWPort, firstPNode, gndEPort, decodeCell);
Export.newInstance(decodeCell, lastPNode.findPortInstFromProto(gndWPort), "GND.m-2.w");
}
NodeInst [] both = new NodeInst[2];
both[0] = lastPNode;
both[1] = lastNode;
return both;
}
private void decExp(Cell nmosCell, NodeInst nNode, Cell decodeCell)
{
int x = 0;
char side = 'n';
String name = "DATA" + x + ".m-1." + side;
Export pp = nmosCell.findExport(name);
while (pp != null)
{
Export.newInstance(decodeCell, nNode.findPortInstFromProto(pp), name);
x++;
name = "DATA" + x + ".m-1." + side;
pp = nmosCell.findExport(name);
}
}
private boolean decodeRoute(Cell pmosCell, NodeInst pNode, Cell nmosCell,
NodeInst nNode, Cell decodeCell, NodeInst firstNode, NodeInst lastNode, boolean inputsOnTop)
{
// Make connection between N and P planes
Export pPort = pmosCell.findExport("DATA0.m-1.n");
Export nPort = nmosCell.findExport("DATA0.m-1.s");
int cnt = 0;
while (pPort != null && nPort != null)
{
// Connect them up here
pla.makeWire(pla.m1Arc, 4, pNode, pPort, nNode, nPort, decodeCell);
// now find the next ports
cnt += 1;
pPort = pmosCell.findExport("DATA" + cnt + ".m-1.n");
nPort = nmosCell.findExport("DATA" + cnt + ".m-1.s");
}
// Make connection between PWR and P-plane
pPort = pmosCell.findExport("DATA0.m-1.s");
nPort = pmosCell.findExport("PWR0.m-1.s");
if (pPort != null && nPort != null)
pla.makeWire(pla.m1Arc, 4, pNode, pPort, pNode, nPort, decodeCell);
Poly poly = pNode.findPortInstFromProto(nPort).getPoly();
double pX = poly.getCenterX();
double pY = poly.getCenterY();
NodeInst pmNode1 = pla.makePin(decodeCell, pX-13, pY, 6, pla.m12Con);
if (pmNode1 == null) return true;
pla.makeWire(pla.m1Arc, 4, pNode, nPort, pmNode1, pmNode1.getProto().getPort(0), decodeCell);
if (!inputsOnTop) // Buffers are at the top of the cell
{
PortProto pwrPort = firstNode.getProto().findPortProto("PWR.m-2.w");
NodeInst pmNode2 = pla.makePin(decodeCell, pX-13, pY+24, 14, pla.m2Pin);
if (pmNode2 == null) return true;
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, firstNode, pwrPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
}
nPort = pPort;
pPort = pmosCell.findExport("DATA1.m-1.s");
cnt = 1;
int pwrCnt = 0;
while (pPort != null && nPort != null)
{
// Connect them up here
pla.makeWire(pla.m1Arc, 4, pNode, pPort, pNode, nPort, decodeCell);
// now find the next ports
cnt += 1;
nPort = pPort;
if ((cnt % 4) == 0)
{
pwrCnt += 1;
String name = "PWR" + pwrCnt + ".m-1.s";
pPort = pmosCell.findExport(name);
if (pPort != null)
pla.makeWire(pla.m1Arc, 4, pNode, pPort, pNode, nPort, decodeCell);
poly = pNode.findPortInstFromProto(pPort).getPoly();
pX = poly.getCenterX();
pY = poly.getCenterY();
NodeInst pmNode2 = pla.makePin(decodeCell, pX-13, pY, 6, pla.m12Con);
if (pmNode2 == null) return true;
pla.makeWire(pla.m1Arc, 4, pNode, pPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pmNode1 = pmNode2;
nPort = pPort;
}
pPort = pmosCell.findExport("DATA" + cnt + ".m-1.s");
}
if (inputsOnTop) // Buffers are at the top of the cell
{
PortProto pwrPort = firstNode.getProto().findPortProto("PWR.m-2.w");
NodeInst pmNode2 = pla.makePin(decodeCell, pX-13, pY-24, 14, pla.m2Pin);
if (pmNode2 == null) return true;
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, firstNode, pwrPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
}
// Make connection between GND and N-plane
nPort = nmosCell.findExport("GND0.m-1.n");
poly = nNode.findPortInstFromProto(nPort).getPoly();
pX = poly.getCenterX();
pY = poly.getCenterY();
pmNode1 = pla.makePin(decodeCell, pX+13, pY, 6, pla.m12Con);
if (pmNode1 == null) return true;
pla.makeWire(pla.m1Arc, 4, nNode, nPort, pmNode1, pmNode1.getProto().getPort(0), decodeCell);
if (!inputsOnTop) // Buffers are at the top of the cell
{
PortProto pwrPort = lastNode.getProto().findPortProto("GND.m-2.e");
NodeInst pmNode2 = pla.makePin(decodeCell, pX+13, pY+90, 14, pla.m2Pin);
if (pmNode2 == null) return true;
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, lastNode, pwrPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
}
cnt = 1;
nPort = nmosCell.findExport("GND" + cnt + ".m-1.n");
while (nPort != null)
{
// Connect them up here
poly = nNode.findPortInstFromProto(nPort).getPoly();
pX = poly.getCenterX();
pY = poly.getCenterY();
NodeInst pmNode2 = pla.makePin(decodeCell, pX+13, pY, 6, pla.m12Con);
if (pmNode2 == null) return true;
pla.makeWire(pla.m1Arc, 4, nNode, nPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pmNode1 = pmNode2;
cnt++;
nPort = nmosCell.findExport("GND" + cnt + ".m-1.n");
}
if (inputsOnTop) // Buffers are at the bottom of the cell
{
PortProto pwrPort = lastNode.getProto().findPortProto("GND.m-2.e");
NodeInst pmNode2 = pla.makePin(decodeCell, pX+13, pY-90, 14, pla.m2Pin);
if (pmNode2 == null) return true;
pla.makeWire(pla.m2Arc, 14, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.m2Arc, 14, lastNode, pwrPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
}
char side = 's';
char acSide = 'e';
if (inputsOnTop)
{
side = 'n';
acSide = 'w';
}
int columns = 2;
Variable var = pmosCell.getVar("PLA_access_rows");
if (var != null) columns = ((Integer)var.getObject()).intValue() / 2; else
System.out.println("DATA_cols defaulting to 2");
int initOffset = 8;
int sep = 7;
cnt = 0;
String name = "ACCESS" + cnt + ".m-1." + acSide;
pPort = pmosCell.findExport(name);
nPort = nmosCell.findExport(name);
while (pPort != null && nPort != null)
{
// wire it
int inCnt = cnt/2;
poly = pNode.findPortInstFromProto(pPort).getPoly();
pX = poly.getCenterX();
poly = nNode.findPortInstFromProto(nPort).getPoly();
double nX = poly.getCenterX();
double nY = poly.getCenterY();
double y, oY;
if (inputsOnTop)
{
y = nY + initOffset + inCnt*sep;
oY = y + (columns - inCnt - 1)*sep;
} else
{
y = nY - initOffset - inCnt*sep;
oY = y - (columns - inCnt - 1)*sep;
}
pmNode1 = pla.makePin(decodeCell, pX, y, 6, pla.mpCon);
if (pmNode1 == null) return true;
NodeInst pmNode2 = pla.makePin(decodeCell, nX, y, 6, pla.mpCon);
if (pmNode2 == null) return true;
pla.makeWire(pla.m1Arc, 4, pmNode1, pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pla.makeWire(pla.pArc, 2, pNode, pPort, pmNode1, pmNode1.getProto().getPort(0), decodeCell);
pla.makeWire(pla.pArc, 2, nNode, nPort, pmNode2, pmNode2.getProto().getPort(0), decodeCell);
pmNode1 = pla.makePin(decodeCell, nX, oY, 4, pla.m1Pin);
if (pmNode1 == null) return true;
pla.makeWire(pla.m1Arc, 4, pmNode1,
pmNode1.getProto().getPort(0), pmNode2, pmNode2.getProto().getPort(0), decodeCell);
Export.newInstance(decodeCell, pmNode1.findPortInstFromProto(pmNode1.getProto().getPort(0)), "INPUT" + inCnt + ".m-1." + side);
cnt += 2; // Only route every second one
name = "ACCESS" + cnt + ".m-1." + acSide;
pPort = pmosCell.findExport(name);
nPort = nmosCell.findExport(name);
}
return false;
}
}