/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: StdCellParams350.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.layout; 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.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.technology.Technology; import com.sun.electric.tool.Job; import com.sun.electric.util.math.DBMath; /** * */ public class StdCellParams350 extends StdCellParams { private static final double minGateWid = 0.6; private static final double maxMosWidth = Double.POSITIVE_INFINITY; private static final double m1OverhangsDiffCont = 0.15; private static final double m1Space = 0.45; private TechType tech; private static void error(boolean pred, String msg) { Job.error(pred, msg); } public static StdCellParams invParams(Technology technology) { StdCellParams stdCell = new StdCellParams350(technology); stdCell.setSizeQuantizationError(0); stdCell.setMaxMosWidth(1000); stdCell.setVddY(5.5); stdCell.setGndY(-4.1); stdCell.setPmosWellHeight(6.4); stdCell.setNmosWellHeight(5.0); // stdCell.setVddExportName("VDD"); // stdCell.setGndExportName("VSS"); stdCell.setSimpleName(true); stdCell.enableNCC("purpleFour"); return stdCell; } private StdCellParams350(Technology tech) { super(tech); this.tech = getTechType(); setGndWidth(1.4); setVddWidth(1.4); } /** Calculate the number of folds and the width of a MOS * transistor. Given that there is a limited physical height into * which a MOS transistor must fit, divide the total required width: * totWid into fingers. Each finger must have width less than or * equal to spaceAvailWid. * * <p> If it is possible, allocate an even number of fingers so that * the left most and right most diffusion contacts may be connected * to power or ground to reducing the capacitance of the inner * switching diffusion contacts. * @param spaceAvailWid the height in the standard cell that is * available for the diffusion of the MOS transistor. * @param totWid the total electrical width required. * @param groupSz This method creates fingers in multiples of * groupSz. For example, if groupSz is 2, then only even numbers of * fingers are created. This is needed when one FoldedMos is * actually going to be wired up as 2 identical, independent * transistors, for example the 2 PMOS pullups for a 2-input NAND * gate. */ public FoldsAndWidth calcFoldsAndWidth( double spaceAvailWid, double totWid, int groupSz) { if (totWid == 0) return null; double maxAvailWid = Math.min(spaceAvailWid, maxMosWidth); int nbGroups = calcNbGroups(maxAvailWid, totWid, groupSz); double gateWid = roundGateWidth(totWid / groupSz / nbGroups); // If we're unfortunate, rounding up gate width causes gate's width // to exceed space available. if (gateWid > maxAvailWid) { nbGroups = calcNbGroups(maxAvailWid - .5, totWid, groupSz); gateWid = roundGateWidth(totWid / groupSz / nbGroups); } double physWid = Math.max(tech.getDiffContWidth(), gateWid); if (gateWid < minGateWid) return null; return new FoldsAndWidth(nbGroups * groupSz, gateWid, physWid); } private int calcNbGroups(double maxAvailWid, double totWid, int groupSz) { int nbGroups = (int) Math.ceil(totWid / maxAvailWid / groupSz); // If groupSz is even then we always create an even number of // fingers and we don't have to add more fingers to reduce // diffusion capacitance. if (groupSz % 2 == 0) return nbGroups; // If nbGroups is even then we always create an even number of // fingers and we don't have to add more fingers to reduce // diffusion capacitance if (nbGroups % 2 == 0) return nbGroups; // if totWid is less than maxAvailWid and groupSz is 1, just // use 1 gate (no fingers) if ((totWid < maxAvailWid) && (groupSz == 1)) return 1; // try adding one more group to get an even number of fingers int roundupGroups = nbGroups + 1; double wid = totWid / groupSz / roundupGroups; // Don't fold if gate width is less than width of diffusion // contact. if (wid >= tech.getDiffContWidth()) nbGroups = roundupGroups; return nbGroups; } /** Wire pmos or nmos to vdd or gnd, respectively. Add an export * if there is none. */ public void wireVddGnd(FoldedMos[] moss, SelectSrcDrn select, Cell p) { FoldedMos mos = moss[0]; PortInst leftDiff = mos.getSrcDrn(0); Cell f = leftDiff.getNodeInst().getParent(); double busWid = mos instanceof FoldedPmos ? getVddWidth() : getGndWidth(); double busY = mos instanceof FoldedPmos ? getVddY() : getGndY(); TrackRouter net = new TrackRouterH(tech.m1(), busWid, busY, tech, p); String exportNm = mos instanceof FoldedPmos ? getVddExportName() : getGndExportName(); if (f.findPortProto(exportNm)==null) { // The export doesn't yet exist. Create and export a metal2 pin // aligned with the first diffusion. double x = leftDiff.getBounds().getCenterX(); NodeInst pinProt = LayoutLib.newNodeInst(tech.m1pin(), x, busY, LayoutLib.DEF_SIZE, LayoutLib.DEF_SIZE, 0, f); PortInst pin = pinProt.getOnlyPortInst(); Export e = Export.newInstance(f, pin, exportNm); PortCharacteristic role = mos instanceof FoldedPmos ? getVddExportRole() : getGndExportRole(); e.setCharacteristic(role); // Connect the export to itself using a standard width power or // ground strap. The width of this strap serves as a hint to // Electric as to the width to use to connect to this export at // the next level up. LayoutLib.newArcInst(tech.m1(), busWid, pin, pin); net.connect(pin); } double diffY = LayoutLib.roundCenterY(leftDiff); double notchLoY = Math.min(busY - busWid / 2, diffY); double notchHiY = Math.max(busY + busWid / 2, diffY); PortInst lastDiff = null; for (int i=0; i<moss.length; i++) { for (int j=0; j<moss[i].nbSrcDrns(); j++) { if (select.connectThisOne(i, j)) { PortInst thisDiff = moss[i].getSrcDrn(j); net.connect(thisDiff); if (lastDiff!=null) { // Check to see if we just created a notch. double leftX = LayoutLib.roundCenterX(lastDiff); double rightX = LayoutLib.roundCenterX(thisDiff); error(leftX>rightX, "wireVddGnd: trans not sorted left to right"); double deltaX = rightX - leftX; if (deltaX>0 && deltaX < m1OverhangsDiffCont*2+m1Space) { // Fill notches, sigh! (This is starting to lose // it's novelty value.) // // Make height integral number of lambdas so // centerY will be on .5 lambda grid and connecting // to center won't generate CIF resolution errors. double dY = Math.ceil(notchHiY - notchLoY); NodeInst patchNode = LayoutLib.newNodeInst(tech.m1Node(), (leftX+rightX)/2, notchLoY+dY/2, deltaX, dY, 0, f); PortInst patch = patchNode.getOnlyPortInst(); LayoutLib.newArcInst(tech.m1(), LayoutLib.DEF_SIZE, patch, thisDiff); } } lastDiff = thisDiff; } } } } /** essential bounds for cells with both NMOS and PMOS */ public void addEssentialBounds(double loX, double hiX, Cell cell) { LayoutLib.newNodeInst(tech.essentialBounds(), loX, getGndY(), LayoutLib.DEF_SIZE, LayoutLib.DEF_SIZE, 180, cell); LayoutLib.newNodeInst(tech.essentialBounds(), hiX, getVddY(), LayoutLib.DEF_SIZE, LayoutLib.DEF_SIZE, 0, cell); } @Override public double roundGateWidth(double w) { return DBMath.round(Math.ceil(w*10.0)/10.0); } public double getDRCRingSpacing() { return 2.3; } }