/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.sun.electric.tool.generator.layout.gates; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.GeometryHandler; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.variable.TextDescriptor; import com.sun.electric.tool.Job; import com.sun.electric.tool.extract.LayerCoverageTool; import com.sun.electric.tool.generator.layout.FoldedMos; import com.sun.electric.tool.generator.layout.FoldedNmos; import com.sun.electric.tool.generator.layout.FoldedPmos; import com.sun.electric.tool.generator.layout.FoldsAndWidth; import com.sun.electric.tool.generator.layout.LayoutLib; import com.sun.electric.tool.generator.layout.StdCellParams; import com.sun.electric.tool.generator.layout.TechType; import com.sun.electric.tool.generator.layout.TrackRouter; import com.sun.electric.tool.generator.layout.TrackRouterH; import com.sun.electric.util.math.Orientation; import java.util.Iterator; /** * * @author dn146861 */ public class Inv350 { private static final double inY = 0.0; private static final double p1_nd_sp = 0; private static final double p1m1_met_wid = 0.8; private static final double m1m2_m1_wid = 0.9; private static final double totWidN = 1.1; private static final double totWidP = 1.7; private static final String nm = "inv{lay}"; private static final double wellOverhangDiff = 1.2; private static final double m1_m1_sp = 0.45; private static final double m1_wid = 0.5; private static final double pd_p1_sp = 0.4; private static final double nd_p1_sp = 0.4; private static void error(boolean pred, String msg) { Job.error(pred, msg); } public static Cell makePart(double sz, String threshold, StdCellParams stdCell) { TechType tech = stdCell.getTechType(); sz = stdCell.roundSize(sz); error(!threshold.equals("") && !threshold.equals("LT") && !threshold.equals("HT"), "Inv: threshold not \"\", \"LT\", or \"HT\": " + threshold); String nm = "inv"+threshold +(stdCell.getDoubleStrapGate() ? "_strap" : ""); sz = stdCell.checkMinStrength(sz, threshold.equals("LT") ? .5 : 1, nm); double p1m1_wid = tech.getP1Width(); double p1_p1_sp = tech.getP1ToP1Space(); double exp_wid = 0.9;//4 double in_wid = 0.8;//3 double outHiY = inY + (in_wid/2 + m1_m1_sp + exp_wid/2); double outLoY = inY - (in_wid/2 + m1_m1_sp + exp_wid/2); // Space needed at the top of the PMOS well and bottom of MOS well. // We need more space if we're double strapping poly. double outsideSpace = stdCell.getDoubleStrapGate() ? ( p1_nd_sp + p1m1_wid + p1_p1_sp/2 ) : ( wellOverhangDiff ); double tranHiInnerY = wellOverhangDiff; double tranLoInnerY = -wellOverhangDiff; // double tranHiInnerY = Math.max(wellOverhangDiff, outHiY + (exp_wid/2 + m1_m1_sp)); // double tranLoInnerY = Math.min(-wellOverhangDiff, outLoY - (exp_wid/2 + m1_m1_sp)); double tranHiOuterY = Math.min(stdCell.getCellTop() - outsideSpace, stdCell.getVddY() - stdCell.getVddWidth()/2 - m1_m1_sp); double tranLoOuterY = Math.max(stdCell.getCellBot() + outsideSpace, stdCell.getGndY() + stdCell.getGndWidth()/2 + m1_m1_sp); // find number of folds and width of PMOS double spaceAvail = tranHiOuterY - tranHiInnerY; double lamPerSz = threshold.equals("HT") ? 3.4 : 1.7; double totWidP = sz * lamPerSz; FoldsAndWidth fwP = stdCell.calcFoldsAndWidth(spaceAvail, totWidP, 1); // find number of folds and width of NMOS spaceAvail = tranLoInnerY - tranLoOuterY; lamPerSz = threshold.equals("LT") ? 2.2 : 1.1; double totWidN = sz * lamPerSz; FoldsAndWidth fwN = stdCell.calcFoldsAndWidth(spaceAvail, totWidN, 1); // create Inverter Part Cell inv = stdCell.findPart(nm, sz); if (inv!=null) return inv; inv = stdCell.newPart(nm, sz); // leave vertical m1 track for in double inX = m1_m1_sp/2 + m1m2_m1_wid/2; Export eIn = LayoutLib.newExport(inv, "in", PortCharacteristic.IN, tech.m1(), exp_wid, inX, inY); double mosX = tech.getDiffContWidth()/2 + tech.getSelectSurroundDiffInTrans() + tech.getSelectSpacingRule()/2; double nmosY = tranLoInnerY - fwN.physWid / 2; FoldedMos nmos = new FoldedNmos(mosX, nmosY, fwN.nbFolds, 1, fwN.gateWid, null, 'C', inv, tech); double pmosY = tranHiInnerY + fwP.physWid / 2; FoldedMos pmos = new FoldedPmos(mosX, pmosY, fwP.nbFolds, 1, fwP.gateWid, null, 'C', inv, tech); // inverter output: m1_wid/2 + m1_m1_sp + m1_wid/2 double rightestGateX = Math.max( nmos.getGate(nmos.nbGates() - 1, 'T').getCenter().getX(), pmos.getGate(pmos.nbGates() - 1, 'B').getCenter().getX()); double outX = rightestGateX + p1m1_met_wid/2 + m1_m1_sp + exp_wid/2; // double outX = StdCellParams.getRightDiffX(nmos, pmos) + m1_wid/2 + m1_m1_sp + m1_wid/2; double outY = 0; Export eOut = LayoutLib.newExport(inv, "out", PortCharacteristic.OUT, tech.m1(), exp_wid, outX, outY); // create vdd and gnd exports and connect to MOS source/drains stdCell.wireVddGnd(nmos, StdCellParams.EVEN, inv); stdCell.wireVddGnd(pmos, StdCellParams.EVEN, inv); // Connect up input. Do PMOS gates first because PMOS gate spacing // is a valid spacing for p1m1 vias even for small strengths. TrackRouter in = new TrackRouterH(tech.p1(), tech.getP1M1Width(), inY, tech, inv); in.connect(eIn); for (int i=0; i<pmos.nbGates(); i++) in.connect(pmos.getGate(i, 'B')); for (int i=0; i<nmos.nbGates(); i++) in.connect(nmos.getGate(i, 'T')); // if (stdCell.getDoubleStrapGate()) { // // Connect gates using metal1 along bottom of cell // double gndBot = stdCell.getGndY() - stdCell.getGndWidth() / 2; // double inLoFromGnd = gndBot -m1_m1_sp -m1_wid/2; // double nmosBot = nmosY - fwN.physWid / 2; // double inLoFromMos = nmosBot -nd_p1_sp - p1m1_wid/2; // double inLoY = Math.min(inLoFromGnd, inLoFromMos); // // TrackRouter inLo = new TrackRouterH(tech.m1(), 3, inLoY, tech, inv); // inLo.connect(eIn); // for (int i = 0; i < nmos.nbGates(); i++) { // inLo.connect(nmos.getGate(i, 'B')); // } // // // Connect gates using metal1 along top of cell // double vddTop = stdCell.getVddY() + stdCell.getVddWidth() / 2; // double inHiFromVdd = vddTop +m1_m1_sp + m1_wid/2; // double pmosTop = pmosY + fwP.physWid / 2; // double inHiFromMos = pmosTop +pd_p1_sp + p1m1_wid/2; // double inHiY = Math.max(inHiFromVdd, inHiFromMos); // // TrackRouter inHi = new TrackRouterH(tech.m1(), 3, inHiY, tech, inv); // inHi.connect(eIn); // for (int i=0; i<pmos.nbGates(); i++) { // inHi.connect(pmos.getGate(i, 'T')); // } // } // connect up output TrackRouter outH = new TrackRouterH(tech.m1(), exp_wid, outY, tech, inv); TrackRouter outHi = outH; // TrackRouter outHi = new TrackRouterH(tech.m1(), exp_wid, outHiY, tech, inv); // outHi.setShareableViaDist(0); outHi.connect(eOut); for (int i=1; i<pmos.nbSrcDrns(); i += 2) { outHi.connect(pmos.getSrcDrn(i)); } TrackRouter outLo = outH; // TrackRouter outLo = new TrackRouterH(tech.m1(), exp_wid, outLoY, tech, inv); outLo.connect(eOut); for (int i = 1; i < nmos.nbSrcDrns(); i += 2) { outLo.connect(nmos.getSrcDrn(i)); } // add wells double wellMinX = 0; double wellMaxX = outX + m1_wid/2 + m1_m1_sp/2; stdCell.addNmosWell(wellMinX, wellMaxX, inv); stdCell.addPmosWell(wellMinX, wellMaxX, inv); double boundsLeftX = 0; double boundsRightX = outX + exp_wid/2 + m1_m1_sp/2; EPoint gndLeft = EPoint.fromLambda(boundsLeftX, stdCell.getGndY()); EPoint gndRight = EPoint.fromLambda(boundsRightX, stdCell.getGndY()); EPoint vddLeft = EPoint.fromLambda(boundsLeftX, stdCell.getVddY()); EPoint vddRight = EPoint.fromLambda(boundsRightX, stdCell.getVddY()); NodeInst gndPinLeft = NodeInst.newInstance(tech.m1pin(), gndLeft, 0, 0, inv); NodeInst gndPinRight = NodeInst.newInstance(tech.m1pin(), gndRight, 0, 0, inv); NodeInst vddPinLeft = NodeInst.newInstance(tech.m1pin(), vddLeft, 0, 0, inv); NodeInst vddPinRight = NodeInst.newInstance(tech.m1pin(), vddRight, 0, 0, inv); ArcInst gndArcLeft = ArcInst.makeInstance(tech.m1(), gndPinLeft.getOnlyPortInst(), inv.findExport("gnd").getOriginalPort()); gndArcLeft.setLambdaBaseWidth(stdCell.getGndWidth()); gndArcLeft.setTailExtended(false); gndArcLeft.setHeadExtended(false); ArcInst gndArcRight = ArcInst.makeInstance(tech.m1(), gndPinRight.getOnlyPortInst(), inv.findExport("gnd").getOriginalPort()); gndArcRight.setLambdaBaseWidth(stdCell.getGndWidth()); gndArcRight.setTailExtended(false); gndArcRight.setHeadExtended(false); ArcInst vddArcLeft = ArcInst.makeInstance(tech.m1(), vddPinLeft.getOnlyPortInst(), inv.findExport("vdd").getOriginalPort()); vddArcLeft.setLambdaBaseWidth(stdCell.getVddWidth()); vddArcLeft.setTailExtended(false); vddArcLeft.setHeadExtended(false); ArcInst vddArcRight = ArcInst.makeInstance(tech.m1(), vddPinRight.getOnlyPortInst(), inv.findExport("vdd").getOriginalPort()); vddArcRight.setLambdaBaseWidth(stdCell.getVddWidth()); vddArcRight.setTailExtended(false); vddArcRight.setHeadExtended(false); NodeInst deviceMark = NodeInst.newInstance(tech.getTechnology().findNodeProto("DeviceMark-Node"), EPoint.fromLambda((boundsRightX + boundsLeftX)/2, (stdCell.getVddY() + stdCell.getGndY())/2), (boundsRightX - boundsLeftX), (stdCell.getVddY() - stdCell.getGndY()), inv); // add essential bounds stdCell.addEssentialBounds(boundsLeftX, boundsRightX, inv); for (Iterator<Export> it = inv.getExports(); it.hasNext(); ) { Export e = it.next(); TextDescriptor td = e.getTextDescriptor(Export.EXPORT_NAME).withRelSize(0.5); e.setTextDescriptor(Export.EXPORT_NAME, td); } double gridTran = 0.10; double epsWidP = fwP.gateWid*fwP.nbFolds - totWidP; int nfixWidP = (int)Math.rint(epsWidP/gridTran); for (int i = pmos.nbGates() - nfixWidP; i < pmos.nbGates(); i++) { pmos.getGate(i, 'B').getNodeInst().modifyInstance(0, 0/*-gridTran/2*/, -gridTran, 0, Orientation.IDENT); pmos.getSrcDrn(i + 1).getNodeInst().modifyInstance(0, 0/*-gridTran/2*/, 0, -gridTran, Orientation.IDENT); } double epsWidN = fwN.gateWid*fwN.nbFolds - totWidN; int nfixWidN = (int)Math.rint(epsWidN/gridTran); for (int i = nmos.nbGates() - nfixWidN; i < nmos.nbGates(); i++) { nmos.getGate(i, 'T').getNodeInst().modifyInstance(0, 0/*gridTran/2*/, -gridTran, 0, Orientation.IDENT); nmos.getSrcDrn(i + 1).getNodeInst().modifyInstance(0, 0/*gridTran/2*/, 0, -gridTran, Orientation.IDENT); } System.out.println(inv.getName() + " " + nfixWidP + " " + nfixWidN); LayerCoverageTool.LayerCoveragePreferences lcp = new LayerCoverageTool.LayerCoveragePreferences(true); LayerCoverageTool.layerCoverageCommand(LayerCoverageTool.LCMode.IMPLANT, GeometryHandler.GHMode.ALGO_SWEEP, inv, false, lcp); // perform Network Consistency Check stdCell.doNCC(inv, nm+"{sch}"); return inv; } }