Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.technology.technologies.MoCMOS Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MoCMOS.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.technology.technologies;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.AbstractShapeBuilder;
import com.sun.electric.technology.DRCTemplate;
import com.sun.electric.technology.Foundry;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.PrimitivePort;
import com.sun.electric.technology.TechFactory;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.XMLRules;
import com.sun.electric.technology.Xml;
import com.sun.electric.tool.user.User;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import java.io.PrintWriter;
import java.util.*;
/**
* This is the MOSIS CMOS technology.
*/
public class MoCMOS extends Technology {
/** Value for standard SCMOS rules. */
public static final int SCMOSRULES = 0;
/** Value for submicron rules. */
public static final int SUBMRULES = 1;
/** Value for deep rules. */
public static final int DEEPRULES = 2;
/** key of Variable for saving technology state. */
public static final Variable.Key TECH_LAST_STATE = Variable.newKey("TECH_last_state");
public static final Version changeOfMetal6 = Version.parseVersion("8.02o"); // Fix of bug #357
private static final Version scmosTransistorSizeBug = Version.parseVersion("8.08h");
private static final Version scmosTransistorSizeFix = Version.parseVersion("8.09d");
private static final String TECH_NAME = "mocmos";
private static final String XML_PREFIX = TECH_NAME + ".";
private static final String PREF_PREFIX = "technology/technologies/";
private static final TechFactory.Param techParamRuleSet =
new TechFactory.Param(XML_PREFIX + "MOCMOS Rule Set", PREF_PREFIX + "MoCMOSRuleSet", Integer.valueOf(1));
private static final TechFactory.Param techParamNumMetalLayers =
new TechFactory.Param(XML_PREFIX + "NumMetalLayers", PREF_PREFIX + TECH_NAME + "NumberOfMetalLayers", Integer.valueOf(6));
private static final TechFactory.Param techParamUseSecondPolysilicon =
new TechFactory.Param(XML_PREFIX + "UseSecondPolysilicon", PREF_PREFIX + TECH_NAME + "SecondPolysilicon", Boolean.TRUE);
private static final TechFactory.Param techParamDisallowStackedVias =
new TechFactory.Param(XML_PREFIX + "DisallowStackedVias", PREF_PREFIX + "MoCMOSDisallowStackedVias", Boolean.FALSE);
private static final TechFactory.Param techParamUseAlternativeActivePolyRules =
new TechFactory.Param(XML_PREFIX + "UseAlternativeActivePolyRules", PREF_PREFIX + "MoCMOSAlternateActivePolyRules", Boolean.FALSE);
private static final TechFactory.Param techParamAnalog =
new TechFactory.Param(XML_PREFIX + "Analog", PREF_PREFIX + TECH_NAME + "Analog", Boolean.FALSE);
// Tech params
private Integer paramRuleSet;
private Boolean paramUseSecondPolysilicon;
private Boolean paramDisallowStackedVias;
private Boolean paramUseAlternativeActivePolyRules;
private Boolean paramAnalog;
// nodes. Storing nodes only whe they are need in outside the constructor
/** metal-1-P/N-active-contacts */
private PrimitiveNode[] metalActiveContactNodes = new PrimitiveNode[2];
/** Scalable Transistors */
private PrimitiveNode[] scalableTransistorNodes = new PrimitiveNode[2];
// -------------------- private and protected methods ------------------------
public MoCMOS(Generic generic, TechFactory techFactory, Map techParams, Xml.Technology t) {
super(generic, techFactory, techParams, t);
paramRuleSet = (Integer) techParams.get(techParamRuleSet);
paramNumMetalLayers = (Integer) techParams.get(techParamNumMetalLayers);
paramUseSecondPolysilicon = (Boolean) techParams.get(techParamUseSecondPolysilicon);
paramDisallowStackedVias = (Boolean) techParams.get(techParamDisallowStackedVias);
paramUseAlternativeActivePolyRules = (Boolean) techParams.get(techParamUseAlternativeActivePolyRules);
paramAnalog = (Boolean) techParams.get(techParamAnalog);
setStaticTechnology();
//setFactoryResolution(0.01); // value in lambdas 0.005um -> 0.05 lambdas
//**************************************** NODES ****************************************
metalActiveContactNodes[P_TYPE] = findNodeProto("Metal-1-P-Active-Con");
metalActiveContactNodes[N_TYPE] = findNodeProto("Metal-1-N-Active-Con");
scalableTransistorNodes[P_TYPE] = findNodeProto("P-Transistor-Scalable");
scalableTransistorNodes[N_TYPE] = findNodeProto("N-Transistor-Scalable");
for (Iterator it = getLayers(); it.hasNext();) {
Layer layer = it.next();
if (!layer.getFunction().isUsed(getNumMetals(), isSecondPolysilicon() ? 2 : 1)) {
layer.getPureLayerNode().setNotUsed(true);
}
}
PrimitiveNode np = findNodeProto("P-Transistor-Scalable");
if (np != null) {
np.setCanShrink();
}
np = findNodeProto("N-Transistor-Scalable");
if (np != null) {
np.setCanShrink();
}
np = findNodeProto("NPN-Transistor");
if (np != null) {
np.setCanShrink();
}
}
/******************** SUPPORT METHODS ********************/
@Override
protected void dumpExtraProjectSettings(PrintWriter out, Map settings) {
printlnSetting(out, settings, getRuleSetSetting());
printlnSetting(out, settings, getSecondPolysiliconSetting());
printlnSetting(out, settings, getDisallowStackedViasSetting());
printlnSetting(out, settings, getAlternateActivePolyRulesSetting());
printlnSetting(out, settings, getAnalogSetting());
}
/******************** SCALABLE TRANSISTOR DESCRIPTION ********************/
/**
* Method to create a new PrimitiveNode from the parameters.
* @param protoName the name of the PrimitiveNode.
* Primitive names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
* @param sizeCorrector size corrector for the PrimitiveNode,
* @param width the width of the PrimitiveNode.
* @param height the height of the PrimitiveNode.
* @param baseRectangle the reported/selected part of the PrimitiveNode with standard size.
* @param layers the Layers that comprise the PrimitiveNode.
* @return the newly created PrimitiveNode.
*/
@Override
protected PrimitiveNode newPrimitiveNode(String protoName, EPoint sizeCorrector1, EPoint sizeCorrector2,
String minSizeRule, double width, double height,
ERectangle fullRectangle, ERectangle baseRectangle, Technology.NodeLayer[] layers) {
if ("N-Transistor-Scalable".equals(protoName) || "P-Transistor-Scalable".equals(protoName)) {
return new ScalableTransistor(protoName, this, sizeCorrector1, sizeCorrector2, minSizeRule, width, height,
fullRectangle, baseRectangle, layers);
} else {
return super.newPrimitiveNode(protoName, sizeCorrector1, sizeCorrector2, minSizeRule, width, height,
fullRectangle, baseRectangle, layers);
}
}
private static final int SCALABLE_ACTIVE_TOP = 0;
private static final int SCALABLE_METAL_TOP = 1;
private static final int SCALABLE_CUT_TOP = 2;
private static final int SCALABLE_ACTIVE_BOT = 3;
private static final int SCALABLE_METAL_BOT = 4;
private static final int SCALABLE_CUT_BOT = 5;
private static final int SCALABLE_ACTIVE_CTR = 6;
private static final int SCALABLE_POLY = 7;
private static final int SCALABLE_WELL = 8;
private static final int SCALABLE_SUBSTRATE = 9;
private static final int SCALABLE_TOTAL = 10;
private class ScalableTransistor extends PrimitiveNode {
ScalableTransistor(String protoName, Technology tech, EPoint sizeCorrector1, EPoint sizeCorrector2, String minSizeRule,
double defWidth, double defHeight, ERectangle fullRectangle, ERectangle baseRectangle, Technology.NodeLayer[] layers) {
super(protoName, tech, sizeCorrector1, sizeCorrector2, minSizeRule, defWidth, defHeight, fullRectangle, baseRectangle, layers);
}
/**
* Puts into shape builder s the polygons that describe node "n", given a set of
* NodeLayer objects to use.
* This method is overridden by specific Technologies.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
*/
@Override
public void genShape(AbstractShapeBuilder b, ImmutableNodeInst n) {
assert n.protoId == getId();
VarContext context = null;
// determine special configurations (number of active contacts, inset of active contacts)
int numContacts = 2;
boolean insetContacts = false;
String pt = n.getVarValue(TRANS_CONTACT, String.class);
if (pt != null) {
for (int i = 0; i < pt.length(); i++) {
char chr = pt.charAt(i);
if (chr == '0' || chr == '1' || chr == '2') {
numContacts = chr - '0';
} else if (chr == 'i' || chr == 'I') {
insetContacts = true;
}
}
}
int boxOffset = 6 - numContacts * 3;
// determine width
double activeWidMax = n.size.getLambdaX() + 3;
// double nodeWid = ni.getXSize();
// double activeWidMax = nodeWid - 14;
double activeWid = activeWidMax;
Variable var = n.getVar(Schematics.ATTR_WIDTH);
if (var != null) {
VarContext evalContext = context;
if (evalContext == null) {
evalContext = VarContext.globalContext;
}
NodeInst ni = null; // dummy node inst
String extra = var.describe(evalContext, ni);
Object o = evalContext.evalVar(var, ni);
if (o != null) {
extra = o.toString();
}
double requestedWid = TextUtils.atof(extra);
if (requestedWid > activeWid) {
System.out.println("Warning: Scalable transistor "
+ n.name + " requests width of " + requestedWid + " but is only " + activeWid + " wide");
}
if (requestedWid < activeWid && requestedWid > 0) {
activeWid = requestedWid;
}
}
double shrinkGate = 0.5 * (activeWidMax - activeWid);
// contacts must be 5 wide at a minimum
double shrinkCon = (int) (0.5 * (activeWidMax + 2 - Math.max(activeWid, 5)));
// now compute the number of polygons
Technology.NodeLayer[] layers = getNodeLayers();
assert layers.length == SCALABLE_TOTAL;
int count = SCALABLE_TOTAL - boxOffset;
Technology.NodeLayer[] newNodeLayers = new Technology.NodeLayer[count];
// load the basic layers
int fillIndex = 0;
for (int box = boxOffset; box < SCALABLE_TOTAL; box++) {
TechPoint[] oldPoints = layers[box].getPoints();
TechPoint[] points = new TechPoint[oldPoints.length];
for (int i = 0; i < oldPoints.length; i++) {
points[i] = oldPoints[i];
}
double shrinkX = 0;
TechPoint p0 = points[0];
TechPoint p1 = points[1];
double x0 = p0.getX().getAdder().getLambda();
double x1 = p1.getX().getAdder().getLambda();
double y0 = p0.getY().getAdder().getLambda();
double y1 = p1.getY().getAdder().getLambda();
switch (box) {
case SCALABLE_ACTIVE_TOP:
case SCALABLE_METAL_TOP:
case SCALABLE_CUT_TOP:
shrinkX = shrinkCon;
if (insetContacts) {
y0 -= 0.5;
y1 -= 0.5;
}
break;
case SCALABLE_ACTIVE_BOT:
case SCALABLE_METAL_BOT:
case SCALABLE_CUT_BOT:
shrinkX = shrinkCon;
if (insetContacts) {
y0 -= 0.5;
y1 -= 0.5;
}
break;
case SCALABLE_ACTIVE_CTR: // active that passes through gate
case SCALABLE_POLY: // poly
shrinkX = shrinkGate;
break;
case SCALABLE_WELL: // well and select
case SCALABLE_SUBSTRATE:
if (insetContacts) {
y0 += 0.5;
y1 -= 0.5;
}
break;
}
x0 += shrinkX;
x1 -= shrinkX;
points[0] = p0.withX(p0.getX().withGridAdder(DBMath.lambdaToGrid(x0))).withY(p0.getY().withGridAdder(DBMath.lambdaToGrid(y0)));
points[1] = p1.withX(p1.getX().withGridAdder(DBMath.lambdaToGrid(x1))).withY(p1.getY().withGridAdder(DBMath.lambdaToGrid(y1)));
Technology.NodeLayer oldNl = layers[box];
if (oldNl.getRepresentation() == NodeLayer.MULTICUTBOX) {
newNodeLayers[fillIndex] = Technology.NodeLayer.makeMulticut(oldNl.getLayer(), oldNl.getPortNum(),
oldNl.getStyle(), points, oldNl.getMulticutSizeX(), oldNl.getMulticutSizeY(), oldNl.getMulticutSep1D(), oldNl.getMulticutSep2D());
} else {
newNodeLayers[fillIndex] = new Technology.NodeLayer(oldNl.getLayer(), oldNl.getPortNum(),
oldNl.getStyle(), oldNl.getRepresentation(), points);
}
fillIndex++;
}
// now let the superclass convert it to Polys
b.genShapeOfNode(n, this, newNodeLayers, null);
}
}
/******************** PARAMETERIZABLE DESIGN RULES ********************/
/**
* Method to build "factory" design rules, given the current technology settings.
* @return the "factory" design rules for this Technology.
* Returns null if there is an error loading the rules.
*/
@Override
protected XMLRules makeFactoryDesignRules() {
Foundry foundry = getSelectedFoundry();
List theRules = foundry.getRules();
XMLRules rules = new XMLRules(this);
boolean pSubstrateProcess = User.isPSubstrateProcessLayoutTechnology();
assert (foundry != null);
// load the DRC tables from the explanation table
int numMetals = getNumMetals();
int rulesMode = getRuleSet();
for (int pass = 0; pass < 2; pass++) {
for (DRCTemplate rule : theRules) {
// see if the rule applies
if (pass == 0) {
if (rule.ruleType == DRCTemplate.DRCRuleType.NODSIZ) {
continue;
}
} else {
if (rule.ruleType != DRCTemplate.DRCRuleType.NODSIZ) {
continue;
}
}
int when = rule.when;
boolean goodrule = true;
if ((when & (DRCTemplate.DRCMode.DE.mode() | DRCTemplate.DRCMode.SU.mode() | DRCTemplate.DRCMode.SC.mode())) != 0) {
switch (rulesMode) {
case DEEPRULES:
if ((when & DRCTemplate.DRCMode.DE.mode()) == 0) {
goodrule = false;
}
break;
case SUBMRULES:
if ((when & DRCTemplate.DRCMode.SU.mode()) == 0) {
goodrule = false;
}
break;
case SCMOSRULES:
if ((when & DRCTemplate.DRCMode.SC.mode()) == 0) {
goodrule = false;
}
break;
}
if (!goodrule) {
continue;
}
}
if ((when & (DRCTemplate.DRCMode.M2.mode() | DRCTemplate.DRCMode.M3.mode() | DRCTemplate.DRCMode.M4.mode() | DRCTemplate.DRCMode.M5.mode() | DRCTemplate.DRCMode.M6.mode())) != 0) {
switch (numMetals) {
case 2:
if ((when & DRCTemplate.DRCMode.M2.mode()) == 0) {
goodrule = false;
}
break;
case 3:
if ((when & DRCTemplate.DRCMode.M3.mode()) == 0) {
goodrule = false;
}
break;
case 4:
if ((when & DRCTemplate.DRCMode.M4.mode()) == 0) {
goodrule = false;
}
break;
case 5:
if ((when & DRCTemplate.DRCMode.M5.mode()) == 0) {
goodrule = false;
}
break;
case 6:
if ((when & DRCTemplate.DRCMode.M6.mode()) == 0) {
goodrule = false;
}
break;
}
if (!goodrule) {
continue;
}
}
if ((when & DRCTemplate.DRCMode.AC.mode()) != 0) {
if (!isAlternateActivePolyRules()) {
continue;
}
}
if ((when & DRCTemplate.DRCMode.NAC.mode()) != 0) {
if (isAlternateActivePolyRules()) {
continue;
}
}
if ((when & DRCTemplate.DRCMode.SV.mode()) != 0) {
if (isDisallowStackedVias()) {
continue;
}
}
if ((when & DRCTemplate.DRCMode.NSV.mode()) != 0) {
if (!isDisallowStackedVias()) {
continue;
}
}
if ((when & DRCTemplate.DRCMode.AN.mode()) != 0) {
if (!isAnalog()) {
continue;
}
}
// get more information about the rule
String proc = "";
if ((when & (DRCTemplate.DRCMode.DE.mode() | DRCTemplate.DRCMode.SU.mode() | DRCTemplate.DRCMode.SC.mode())) != 0) {
switch (rulesMode) {
case DEEPRULES:
proc = "DEEP";
break;
case SUBMRULES:
proc = "SUBM";
break;
case SCMOSRULES:
proc = "SCMOS";
break;
}
}
String metal = "";
if ((when & (DRCTemplate.DRCMode.M2.mode() | DRCTemplate.DRCMode.M3.mode() | DRCTemplate.DRCMode.M4.mode() | DRCTemplate.DRCMode.M5.mode() | DRCTemplate.DRCMode.M6.mode())) != 0) {
switch (getNumMetals()) {
case 2:
metal = "2m";
break;
case 3:
metal = "3m";
break;
case 4:
metal = "4m";
break;
case 5:
metal = "5m";
break;
case 6:
metal = "6m";
break;
}
if (!goodrule) {
continue;
}
}
String ruleName = rule.ruleName;
String extraString = metal + proc;
if (extraString.length() > 0 && ruleName.indexOf(extraString) == -1) {
rule = new DRCTemplate(rule);
rule.ruleName += ", " + extraString;
}
rules.loadDRCRules(this, foundry, rule, pSubstrateProcess);
}
}
return rules;
}
@Override
public SizeCorrector getSizeCorrector(Version version, Map projectSettings, boolean isJelib, boolean keepExtendOverMin) {
SizeCorrector sc = super.getSizeCorrector(version, projectSettings, isJelib, keepExtendOverMin);
int ruleSet = SUBMRULES;
Object ruleSetValue = projectSettings.get(getRuleSetSetting());
if (ruleSetValue instanceof Integer) {
ruleSet = ((Integer) ruleSetValue).intValue();
}
if (ruleSet == SCMOSRULES && version.compareTo(scmosTransistorSizeBug) >= 0 && version.compareTo(scmosTransistorSizeFix) < 0) {
setNodeCorrection(sc, "P-Transistor", 1, 2);
setNodeCorrection(sc, "N-Transistor", 1, 2);
}
if (!keepExtendOverMin) {
return sc;
}
boolean newDefaults = version.compareTo(Version.parseVersion("8.04u")) >= 0;
int numMetals = newDefaults ? 6 : 4;
boolean isSecondPolysilicon = newDefaults ? true : false;
Object numMetalsValue = projectSettings.get(getNumMetalsSetting());
if (numMetalsValue instanceof Integer) {
numMetals = ((Integer) numMetalsValue).intValue();
}
Object secondPolysiliconValue = projectSettings.get(getSecondPolysiliconSetting());
if (secondPolysiliconValue instanceof Boolean) {
isSecondPolysilicon = ((Boolean) secondPolysiliconValue).booleanValue();
} else if (secondPolysiliconValue instanceof Integer) {
isSecondPolysilicon = ((Integer) secondPolysiliconValue).intValue() != 0;
}
if (numMetals == getNumMetals() && isSecondPolysilicon == isSecondPolysilicon() && ruleSet == getRuleSet() && version.compareTo(changeOfMetal6) >= 0) {
return sc;
}
setArcCorrection(sc, "Polysilicon-2", ruleSet == SCMOSRULES ? 3 : 7);
setArcCorrection(sc, "Metal-3", numMetals <= 3 ? (ruleSet == SCMOSRULES ? 6 : 5) : 3);
setArcCorrection(sc, "Metal-4", numMetals <= 4 ? 6 : 3);
setArcCorrection(sc, "Metal-5", numMetals <= 5 ? 4 : 3);
if (version.compareTo(changeOfMetal6) < 0) // Fix of bug #357
{
setArcCorrection(sc, "Metal-6", 4);
}
return sc;
}
/******************** OPTIONS ********************/
private final Setting cacheRuleSet = makeIntSetting("MoCMOSRuleSet", "Technology tab", "MOSIS CMOS rule set",
techParamRuleSet.xmlPath.substring(TECH_NAME.length() + 1), 1, "SCMOS", "Submicron", "Deep");
/**
* Method to tell the current rule set for this Technology if Mosis is the foundry.
* @return the current rule set for this Technology:
* 0: SCMOS rules
* 1: Submicron rules (the default)
* 2: Deep rules
*/
public int getRuleSet() {
return paramRuleSet.intValue();
}
// private static DRCTemplate.DRCMode getRuleMode()
// {
// switch (getRuleSet())
// {
// case DEEPRULES: return DRCTemplate.DRCMode.DE;
// case SUBMRULES: return DRCTemplate.DRCMode.SU;
// case SCMOSRULES: return DRCTemplate.DRCMode.SC;
// }
// return null;
// }
/**
* Method to set the rule set for this Technology.
* @return the new rule setting for this Technology, with values:
* 0: SCMOS rules
* 1: Submicron rules
* 2: Deep rules
*/
public Setting getRuleSetSetting() {
return cacheRuleSet;
}
private final Setting cacheSecondPolysilicon = makeBooleanSetting(getTechName() + "SecondPolysilicon", "Technology tab", getTechName().toUpperCase() + " CMOS: Second Polysilicon Layer",
techParamUseSecondPolysilicon.xmlPath.substring(TECH_NAME.length() + 1), true);
/**
* Method to tell the number of polysilicon layers in this Technology.
* The default is false.
* @return true if there are 2 polysilicon layers in this Technology.
* If false, there is only 1 polysilicon layer.
*/
public boolean isSecondPolysilicon() {
return paramUseSecondPolysilicon.booleanValue();
}
/**
* Returns project preferences to tell a second polysilicon layer in this Technology.
* @return project preferences to tell a second polysilicon layer in this Technology.
*/
public Setting getSecondPolysiliconSetting() {
return cacheSecondPolysilicon;
}
private final Setting cacheDisallowStackedVias = makeBooleanSetting("MoCMOSDisallowStackedVias", "Technology tab", "MOSIS CMOS: Disallow Stacked Vias",
techParamDisallowStackedVias.xmlPath.substring(TECH_NAME.length() + 1), false);
/**
* Method to determine whether this Technology disallows stacked vias.
* The default is false (they are allowed).
* @return true if the MOCMOS technology disallows stacked vias.
*/
public boolean isDisallowStackedVias() {
return paramDisallowStackedVias.booleanValue();
}
/**
* Returns project preferences to tell whether this Technology disallows stacked vias.
* @return project preferences to tell whether this Technology disallows stacked vias.
*/
public Setting getDisallowStackedViasSetting() {
return cacheDisallowStackedVias;
}
private final Setting cacheAlternateActivePolyRules = makeBooleanSetting("MoCMOSAlternateActivePolyRules", "Technology tab", "MOSIS CMOS: Alternate Active and Poly Contact Rules",
techParamUseAlternativeActivePolyRules.xmlPath.substring(TECH_NAME.length() + 1), false);
/**
* Method to determine whether this Technology is using alternate Active and Poly contact rules.
* The default is false.
* @return true if the MOCMOS technology is using alternate Active and Poly contact rules.
*/
public boolean isAlternateActivePolyRules() {
return paramUseAlternativeActivePolyRules.booleanValue();
}
/**
* Returns project preferences to tell whether this Technology is using alternate Active and Poly contact rules.
* @return project preferences to tell whether this Technology is using alternate Active and Poly contact rules.
*/
public Setting getAlternateActivePolyRulesSetting() {
return cacheAlternateActivePolyRules;
}
private final Setting cacheAnalog = makeBooleanSetting(getTechName() + "Analog", "Technology tab", "MOSIS CMOS: Analog",
techParamAnalog.xmlPath.substring(TECH_NAME.length() + 1), false);
/**
* Method to tell whether this technology provides analog elements.
* The default is false.
* @return true if this Technology provides analog elements..
*/
public boolean isAnalog() {
return paramAnalog.booleanValue();
}
/**
* Returns project preferences to tell whether this technology provides analog elements.
* @return project preferences to tell whether this technology provides analog elements.
*/
public Setting getAnalogSetting() {
return cacheAnalog;
}
/** set if no stacked vias allowed */
private static final int MOCMOSNOSTACKEDVIAS = 01;
// /** set for stick-figure display */ private static final int MOCMOSSTICKFIGURE = 02;
/** number of metal layers */
private static final int MOCMOSMETALS = 034;
/** 2-metal rules */
private static final int MOCMOS2METAL = 0;
/** 3-metal rules */
private static final int MOCMOS3METAL = 04;
/** 4-metal rules */
private static final int MOCMOS4METAL = 010;
/** 5-metal rules */
private static final int MOCMOS5METAL = 014;
/** 6-metal rules */
private static final int MOCMOS6METAL = 020;
/** type of rules */
private static final int MOCMOSRULESET = 0140;
/** set if submicron rules in use */
private static final int MOCMOSSUBMRULES = 0;
/** set if deep rules in use */
private static final int MOCMOSDEEPRULES = 040;
/** set if standard SCMOS rules in use */
private static final int MOCMOSSCMOSRULES = 0100;
/** set to use alternate active/poly rules */
private static final int MOCMOSALTAPRULES = 0200;
/** set to use second polysilicon layer */
private static final int MOCMOSTWOPOLY = 0400;
// /** set to show special transistors */ private static final int MOCMOSSPECIALTRAN = 01000;
/**
* Method to convert any old-style state information to the new options.
*/
/**
* Method to convert any old-style variable information to the new options.
* May be overrideen in subclasses.
* @param varName name of variable
* @param value value of variable
* @return true if variable was converted
*/
@Override
public Map convertOldVariable(String varName, Object value) {
if (varName.equals("MoCMOSNumberOfMetalLayers") || varName.equals("MOCMOSNumberOfMetalLayers")) {
return Collections.singletonMap(getNumMetalsSetting(), value);
}
if (varName.equals("MoCMOSSecondPolysilicon")) {
return Collections.singletonMap(getSecondPolysiliconSetting(), value);
}
if (!varName.equalsIgnoreCase(TECH_LAST_STATE.getName())) {
return null;
}
if (!(value instanceof Integer)) {
return null;
}
int oldBits = ((Integer) value).intValue();
HashMap settings = new HashMap();
boolean oldNoStackedVias = (oldBits & MOCMOSNOSTACKEDVIAS) != 0;
settings.put(getDisallowStackedViasSetting(), new Integer(oldNoStackedVias ? 1 : 0));
int numMetals = 0;
switch (oldBits & MOCMOSMETALS) {
case MOCMOS2METAL:
numMetals = 2;
break;
case MOCMOS3METAL:
numMetals = 3;
break;
case MOCMOS4METAL:
numMetals = 4;
break;
case MOCMOS5METAL:
numMetals = 5;
break;
case MOCMOS6METAL:
numMetals = 6;
break;
}
settings.put(getNumMetalsSetting(), new Integer(numMetals));
int ruleSet = 0;
switch (oldBits & MOCMOSRULESET) {
case MOCMOSSUBMRULES:
ruleSet = SUBMRULES;
break;
case MOCMOSDEEPRULES:
ruleSet = DEEPRULES;
break;
case MOCMOSSCMOSRULES:
ruleSet = SCMOSRULES;
break;
}
settings.put(getRuleSetSetting(), new Integer(ruleSet));
boolean alternateContactRules = (oldBits & MOCMOSALTAPRULES) != 0;
settings.put(getAlternateActivePolyRulesSetting(), new Integer(alternateContactRules ? 1 : 0));
boolean secondPoly = (oldBits & MOCMOSTWOPOLY) != 0;
settings.put(getSecondPolysiliconSetting(), new Integer(secondPoly ? 1 : 0));
return settings;
}
/**
* This method is called from TechFactory by reflection. Don't remove.
* Returns a list of TechFactory.Params affecting this Technology
* @return list of TechFactory.Params affecting this Technology
*/
public static List getTechParams() {
return Arrays.asList(
techParamRuleSet,
techParamNumMetalLayers,
techParamUseSecondPolysilicon,
techParamDisallowStackedVias,
techParamUseAlternativeActivePolyRules,
techParamAnalog);
}
/**
* This method is called from TechFactory by reflection. Don't remove.
* Returns patched Xml description of this Technology for specified technology params
* @param params values of technology params
* @return patched Xml description of this Technology
*/
public static Xml.Technology getPatchedXml(Map params) {
int ruleSet = ((Integer) params.get(techParamRuleSet)).intValue();
int numMetals = ((Integer) params.get(techParamNumMetalLayers)).intValue();
boolean secondPolysilicon = ((Boolean) params.get(techParamUseSecondPolysilicon)).booleanValue();
boolean disallowStackedVias = ((Boolean) params.get(techParamDisallowStackedVias)).booleanValue();
boolean alternateContactRules = ((Boolean) params.get(techParamUseAlternativeActivePolyRules)).booleanValue();
boolean isAnalog = ((Boolean) params.get(techParamAnalog)).booleanValue();
Xml.Technology tech = Xml.parseTechnology(MoCMOS.class.getResource("mocmos.xml"));
if (tech == null) // errors while reading the XML file
{
return null;
}
Xml.Layer[] metalLayers = new Xml.Layer[6];
Xml.ArcProto[] metalArcs = new Xml.ArcProto[6];
Xml.ArcProto[] activeArcs = new Xml.ArcProto[2];
Xml.ArcProto[] polyArcs = new Xml.ArcProto[6];
Xml.PrimitiveNodeGroup[] metalPinNodes = new Xml.PrimitiveNodeGroup[9];
Xml.PrimitiveNodeGroup[] activePinNodes = new Xml.PrimitiveNodeGroup[2];
Xml.PrimitiveNodeGroup[] polyPinNodes = new Xml.PrimitiveNodeGroup[2];
Xml.PrimitiveNodeGroup[] metalContactNodes = new Xml.PrimitiveNodeGroup[8];
Xml.PrimitiveNodeGroup[] metalWellContactNodes = new Xml.PrimitiveNodeGroup[2];
Xml.PrimitiveNodeGroup[] metalActiveContactNodes = new Xml.PrimitiveNodeGroup[2];
List metal1PolyContactNodes = new ArrayList(4);
Xml.PrimitiveNodeGroup[] transistorNodeGroups = new Xml.PrimitiveNodeGroup[2];
Xml.PrimitiveNodeGroup[] scalableTransistorNodes = new Xml.PrimitiveNodeGroup[2];
Xml.PrimitiveNodeGroup npnTransistorNode = tech.findNodeGroup("NPN-Transistor");
Xml.PrimitiveNodeGroup polyCapNode = tech.findNodeGroup("Poly1-Poly2-Capacitor");
Set analogElems = new HashSet();
analogElems.add(tech.findNodeGroup("N-Active-Resistor"));
analogElems.add(tech.findNodeGroup("N-No-Silicide-Poly-Resistor"));
analogElems.add(tech.findNodeGroup("N-Well-Resistor"));
analogElems.add(tech.findNodeGroup("P-Well-Resistor"));
analogElems.add(tech.findNodeGroup("P-No-Silicide-Poly-Resistor"));
analogElems.add(tech.findNodeGroup("P-Poly-Resistor"));
analogElems.add(tech.findNodeGroup("NPN-Transistor"));
analogElems.add(tech.findNodeGroup("P-Active-Resistor"));
analogElems.add(tech.findNodeGroup("N-Poly-Resistor"));
analogElems.add(tech.findNodeGroup("Hi-Res-Poly2-Resistor"));
// Remove all possible null entries (not found elements)
analogElems.remove(null);
assert (analogElems.size() == 10 && polyCapNode != null); // so far
for (int i = 0; i < metalLayers.length; i++) {
metalLayers[i] = tech.findLayer("Metal-" + (i + 1));
metalArcs[i] = tech.findArc("Metal-" + (i + 1));
metalPinNodes[i] = tech.findNodeGroup("Metal-" + (i + 1) + "-Pin");
if (i >= metalContactNodes.length) {
continue;
}
metalContactNodes[i] = tech.findNodeGroup("Metal-" + (i + 1) + "-Metal-" + (i + 2) + "-Con");
}
for (int i = 0; i < 2; i++) {
polyArcs[i] = tech.findArc("Polysilicon-" + (i + 1));
polyPinNodes[i] = tech.findNodeGroup("Polysilicon-" + (i + 1) + "-Pin");
metal1PolyContactNodes.add(tech.findNodeGroup("Metal-1-Polysilicon-" + (i + 1) + "-Con"));
}
metal1PolyContactNodes.add(tech.findNodeGroup("Metal-1-Polysilicon-1-2-Con"));
metal1PolyContactNodes.add(polyCapNode); // treating polyCapNode as contact for the resizing
for (int i = P_TYPE; i <= N_TYPE; i++) {
String ts = i == P_TYPE ? "P" : "N";
activeArcs[i] = tech.findArc(ts + "-Active");
activePinNodes[i] = tech.findNodeGroup(ts + "-Active-Pin");
metalWellContactNodes[i] = tech.findNodeGroup("Metal-1-" + ts + "-Well-Con");
metalActiveContactNodes[i] = tech.findNodeGroup("Metal-1-" + ts + "-Active-Con");
transistorNodeGroups[i] = tech.findNodeGroup(ts + "-Transistor");
scalableTransistorNodes[i] = tech.findNodeGroup(ts + "-Transistor-Scalable");
}
String rules = "";
switch (ruleSet) {
case SCMOSRULES:
rules = "now standard";
break;
case DEEPRULES:
rules = "now deep";
break;
case SUBMRULES:
rules = "now submicron";
break;
}
int numPolys = 1;
if (secondPolysilicon) {
numPolys = 2;
}
String description = "MOSIS CMOS (2-6 metals [now " + numMetals + "], 1-2 polys [now "
+ numPolys + "], flex rules [" + rules + "]";
if (disallowStackedVias) {
description += ", stacked vias disallowed";
}
if (alternateContactRules) {
description += ", alternate contact rules";
}
description += ")";
tech.description = description;
Xml.NodeLayer nl;
ResizeData rd = new ResizeData(ruleSet, numMetals, alternateContactRules);
for (int i = 0; i < 6; i++) {
resizeArcPin(metalArcs[i], metalPinNodes[i], 0.5 * rd.metal_width[i]);
if (i >= 5) {
continue;
}
Xml.PrimitiveNodeGroup via = metalContactNodes[i];
nl = via.nodeLayers.get(2);
nl.sizex = nl.sizey = rd.via_size[i];
nl.sep1d = rd.via_inline_spacing[i];
nl.sep2d = rd.via_array_spacing[i];
if (i + 1 >= numMetals) {
continue;
}
double upperHalfSize = 0.5 * rd.via_size[i] + rd.via_overhang[i + 1];
double lowerHalfSize = upperHalfSize;
if (false) {
lowerHalfSize = 0.5 * rd.via_size[i] + rd.via_overhang[i];
}
resizeSquare(via, upperHalfSize, lowerHalfSize, upperHalfSize, 0);
}
for (int i = P_TYPE; i <= N_TYPE; i++) {
double activeE = 0.5 * rd.diff_width;
double wellE = activeE + rd.nwell_overhang_diff_p;
double selectE = activeE + rd.pplus_overhang_diff;
resizeArcPin(activeArcs[i], activePinNodes[i], activeE, wellE, selectE);
Xml.PrimitiveNodeGroup con = metalActiveContactNodes[i];
double metalC = 0.5 * rd.contact_size + rd.contact_metal_overhang_all_sides;
double activeC = 0.5 * rd.contact_size + rd.diff_contact_overhang;
double wellC = activeC + rd.nwell_overhang_diff_p;
double selectC = activeC + rd.nplus_overhang_diff;
resizeSquare(con, activeC, metalC, activeC, wellC, selectC, 0);
resizeContacts(con, rd);
con = metalWellContactNodes[i];
wellC = activeC + rd.nwell_overhang_diff_n;
resizeSquare(con, activeC, metalC, activeC, wellC, selectC, 0);
resizeContacts(con, rd);
resizeSerpentineTransistor(transistorNodeGroups[i], rd);
resizeScalableTransistor(scalableTransistorNodes[i], rd);
}
resizeContacts(npnTransistorNode, rd);
{
Xml.PrimitiveNodeGroup con = metal1PolyContactNodes.get(0);
double metalC = 0.5 * rd.contact_size + rd.contact_metal_overhang_all_sides;
double polyC = 0.5 * rd.contact_size + rd.contact_poly_overhang;
resizeSquare(con, polyC, metalC, polyC, 0);
}
for (Xml.PrimitiveNodeGroup g : metal1PolyContactNodes) {
resizeContacts(g, rd);
}
resizeArcPin(polyArcs[0], polyPinNodes[0], 0.5 * rd.poly_width);
resizeArcPin(polyArcs[1], polyPinNodes[1], 0.5 * rd.poly2_width);
for (int i = numMetals; i < 6; i++) {
metalArcs[i].notUsed = true;
metalPinNodes[i].notUsed = true;
metalContactNodes[i - 1].notUsed = true;
// Remove palette rows with unused metal
assert tech.menuPalette.menuBoxes.get(3 * (6 + numMetals)).get(0) == metalArcs[i];
tech.menuPalette.menuBoxes.remove(3 * (6 + numMetals));
tech.menuPalette.menuBoxes.remove(3 * (6 + numMetals));
tech.menuPalette.menuBoxes.remove(3 * (6 + numMetals));
}
// Clear palette box with unused contact
tech.menuPalette.menuBoxes.get(3 * (6 + numMetals) - 1).clear();
if (!secondPolysilicon) {
polyArcs[1].notUsed = true;
polyPinNodes[1].notUsed = true;
metal1PolyContactNodes.get(1).notUsed = true;
metal1PolyContactNodes.get(2).notUsed = true;
// Remove palette row with polysilicon-2
assert tech.menuPalette.menuBoxes.get(3 * 5).get(0) == polyArcs[1];
tech.menuPalette.menuBoxes.remove(3 * 5);
tech.menuPalette.menuBoxes.remove(3 * 5);
tech.menuPalette.menuBoxes.remove(3 * 5);
}
boolean polyFlag, analogFlag;
if (isAnalog) {
analogFlag = false;
polyFlag = false;
// Clear palette box with capacitor if poly2 is on
if (!secondPolysilicon) {
assert ((Xml.MenuNodeInst) tech.menuPalette.menuBoxes.get(0).get(1)).protoName.equals(polyCapNode.nodes.get(0).name);
// location of capacitor
tech.menuPalette.menuBoxes.get(0).remove(1);
polyFlag = true;
}
} else {
// Clear palette box with NPN transisitor
assert tech.menuPalette.menuBoxes.get(0).get(0) == npnTransistorNode.nodes.get(0);
tech.menuPalette.menuBoxes.get(0).clear();
analogFlag = true;
polyFlag = true;
}
if (polyCapNode != null) {
polyCapNode.notUsed = polyFlag;
}
for (Xml.PrimitiveNodeGroup elem : analogElems) {
if (elem != null) {
elem.notUsed = analogFlag;
}
}
return tech;
}
private static void resizeArcPin(Xml.ArcProto a, Xml.PrimitiveNodeGroup ng, double... exts) {
assert a.arcLayers.size() == exts.length;
assert ng.nodeLayers.size() == exts.length;
double baseExt = exts[0];
double maxExt = 0;
for (int i = 0; i < exts.length; i++) {
Xml.ArcLayer al = a.arcLayers.get(i);
Xml.NodeLayer nl = ng.nodeLayers.get(i);
double ext = exts[i];
assert al.layer.equals(nl.layer);
assert nl.representation == Technology.NodeLayer.BOX;
al.extend.value = ext;
nl.hx.value = nl.hy.value = ext;
nl.lx.value = nl.ly.value = ext == 0 ? 0 : -ext;
maxExt = Math.max(maxExt, ext);
}
Integer version2 = Integer.valueOf(2);
if (baseExt != 0) {
a.diskOffset.put(version2, Double.valueOf(baseExt));
} else {
a.diskOffset.clear();
}
ng.baseLX.value = ng.baseLY.value = baseExt != 0 ? -baseExt : 0;
ng.baseHX.value = ng.baseHY.value = baseExt;
// n.setDefSize
}
private static void resizeSquare(Xml.PrimitiveNodeGroup ng, double base, double... size) {
assert size.length == ng.nodeLayers.size();
double maxSz = 0;
for (int i = 0; i < ng.nodeLayers.size(); i++) {
Xml.NodeLayer nl = ng.nodeLayers.get(i);
assert nl.representation == Technology.NodeLayer.BOX || nl.representation == Technology.NodeLayer.MULTICUTBOX;
double sz = size[i];
assert sz >= 0;
nl.hx.value = nl.hy.value = sz;
nl.lx.value = nl.ly.value = sz == 0 ? 0 : -sz;
maxSz = Math.max(maxSz, sz);
}
Integer version1 = Integer.valueOf(1);
Integer version2 = Integer.valueOf(2);
EPoint sizeCorrector1 = ng.diskOffset.get(version1);
EPoint sizeCorrector2 = ng.diskOffset.get(version2);
if (sizeCorrector2 == null) {
sizeCorrector2 = EPoint.ORIGIN;
}
if (sizeCorrector1 == null) {
sizeCorrector1 = sizeCorrector2;
}
ng.baseLX.value = ng.baseLY.value = base != 0 ? -base : 0;
ng.baseHX.value = ng.baseHY.value = base;
sizeCorrector2 = EPoint.fromLambda(base, base);
ng.diskOffset.put(version2, sizeCorrector2);
if (sizeCorrector1.equals(sizeCorrector2)) {
ng.diskOffset.remove(version1);
} else {
ng.diskOffset.put(version1, sizeCorrector1);
}
}
private static void resizeContacts(Xml.PrimitiveNodeGroup ng, ResizeData rd) {
if (ng == null) {
return;
}
for (Xml.NodeLayer nl : ng.nodeLayers) {
if (nl.representation != Technology.NodeLayer.MULTICUTBOX) {
continue;
}
nl.sizex = nl.sizey = rd.contact_size;
nl.sep1d = rd.contact_spacing;
nl.sep2d = rd.contact_array_spacing;
}
}
private static void resizeSerpentineTransistor(Xml.PrimitiveNodeGroup transistor, ResizeData rd) {
Xml.NodeLayer activeTNode = transistor.nodeLayers.get(0); // active Top or Left
Xml.NodeLayer activeBNode = transistor.nodeLayers.get(1); // active Bottom or Right
Xml.NodeLayer polyCNode = transistor.nodeLayers.get(2); // poly center
Xml.NodeLayer polyLNode = transistor.nodeLayers.get(3); // poly left or Top
Xml.NodeLayer polyRNode = transistor.nodeLayers.get(4); // poly right or bottom
Xml.NodeLayer activeNode = transistor.nodeLayers.get(5); // active
Xml.NodeLayer polyNode = transistor.nodeLayers.get(6); // poly
Xml.NodeLayer wellNode = transistor.nodeLayers.get(7); // well
Xml.NodeLayer selNode = transistor.nodeLayers.get(8); // select
Xml.NodeLayer thickNode = transistor.nodeLayers.get(9); // thick
double hw = 0.5 * rd.gate_width;
double hl = 0.5 * rd.gate_length;
double gateX = hw;
double gateY = hl;
double polyX = gateX + rd.poly_endcap;
double polyY = gateY;
double diffX = gateX;
double diffY = gateY + rd.diff_poly_overhang;
double wellX = diffX + rd.nwell_overhang_diff_p;
double wellY = diffY + rd.nwell_overhang_diff_p;
double selX = diffX + rd.pplus_overhang_diff;
double selY = diffY + rd.pplus_overhang_diff;
double thickX = diffX + rd.thick_overhang;
double thickY = diffY + rd.thick_overhang;
resizeSerpentineLayer(activeTNode, hw, -gateX, gateX, gateY, diffY);
resizeSerpentineLayer(activeBNode, hw, -diffX, diffX, -diffY, -gateY);
resizeSerpentineLayer(polyCNode, hw, -gateX, gateX, -gateY, gateY);
resizeSerpentineLayer(polyLNode, hw, -polyX, -gateX, -polyY, polyY);
resizeSerpentineLayer(polyRNode, hw, gateX, polyX, -polyY, polyY);
resizeSerpentineLayer(activeNode, hw, -diffX, diffX, -diffY, diffY);
resizeSerpentineLayer(polyNode, hw, -polyX, polyX, -polyY, polyY);
resizeSerpentineLayer(wellNode, hw, -wellX, wellX, -wellY, wellY);
resizeSerpentineLayer(selNode, hw, -selX, selX, -selY, selY);
resizeSerpentineLayer(thickNode, hw, -thickX, thickX, -thickY, thickY);
}
private static void resizeSerpentineLayer(Xml.NodeLayer nl, double hw, double lx, double hx, double ly, double hy) {
nl.lx.value = lx;
nl.hx.value = hx;
nl.ly.value = ly;
nl.hy.value = hy;
nl.lWidth = nl.hy.k == 1 ? hy : 0;
nl.rWidth = nl.ly.k == -1 ? -ly : 0;
nl.tExtent = nl.hx.k == 1 ? hx - hw : 0;
nl.bExtent = nl.lx.k == -1 ? -lx - hw : 0;
}
private static void resizeScalableTransistor(Xml.PrimitiveNodeGroup transistor, ResizeData rd) {
Xml.NodeLayer activeTNode = transistor.nodeLayers.get(SCALABLE_ACTIVE_TOP); // active Top
Xml.NodeLayer metalTNode = transistor.nodeLayers.get(SCALABLE_METAL_TOP); // metal Top
Xml.NodeLayer cutTNode = transistor.nodeLayers.get(SCALABLE_CUT_TOP);
Xml.NodeLayer activeBNode = transistor.nodeLayers.get(SCALABLE_ACTIVE_BOT); // active Bottom
Xml.NodeLayer metalBNode = transistor.nodeLayers.get(SCALABLE_METAL_BOT); // metal Bot
Xml.NodeLayer cutBNode = transistor.nodeLayers.get(SCALABLE_CUT_BOT);
Xml.NodeLayer activeCNode = transistor.nodeLayers.get(SCALABLE_ACTIVE_CTR); // active center
Xml.NodeLayer polyCNode = transistor.nodeLayers.get(SCALABLE_POLY); // poly center
Xml.NodeLayer wellNode = transistor.nodeLayers.get(SCALABLE_WELL); // well
Xml.NodeLayer selNode = transistor.nodeLayers.get(SCALABLE_SUBSTRATE); // select
double hw = 0.5 * rd.gate_width;
double hl = 0.5 * rd.gate_length;
double gateX = hw;
double gateY = hl;
double polyX = gateX + rd.poly_endcap;
double polyY = gateY;
double diffX = gateX;
double diffY = gateY + rd.diff_poly_overhang;
// double wellX = diffX + rd.nwell_overhang_diff_p;
// double wellY = diffY + rd.nwell_overhang_diff_p;
// double selX = diffX + rd.pplus_overhang_diff;
// double selY = diffY + rd.pplus_overhang_diff;
double metalC = 0.5 * rd.contact_size + rd.contact_metal_overhang_all_sides;
double activeC = 0.5 * rd.contact_size + rd.diff_contact_overhang;
double wellC = activeC + rd.nwell_overhang_diff_p;
double selectC = activeC + rd.nplus_overhang_diff;
double cutY = hl + rd.poly_diff_spacing + activeC;
resizeScalableLayer(activeTNode, -activeC, activeC, cutY - activeC, cutY + activeC);
resizeScalableLayer(metalTNode, -metalC, metalC, cutY - metalC, cutY + metalC);
resizeScalableLayer(cutTNode, 0, 0, cutY, cutY);
resizeScalableLayer(activeBNode, -activeC, activeC, -cutY - activeC, -cutY + activeC);
resizeScalableLayer(metalBNode, -metalC, metalC, -cutY - metalC, -cutY + metalC);
resizeScalableLayer(cutBNode, 0, 0, -cutY, -cutY);
resizeScalableLayer(activeCNode, -diffX, diffX, -diffY, diffY);
resizeScalableLayer(polyCNode, -polyX, polyX, -polyY, polyY);
resizeScalableLayer(wellNode, -wellC, wellC, -cutY - wellC, cutY + wellC);
resizeScalableLayer(selNode, -selectC, selectC, -cutY - selectC, cutY + selectC);
resizeContacts(transistor, rd);
}
private static void resizeScalableLayer(Xml.NodeLayer nl, double lx, double hx, double ly, double hy) {
nl.lx.value = lx;
nl.hx.value = hx;
nl.ly.value = ly;
nl.hy.value = hy;
}
private static class ResizeData {
private final double diff_width = 3; // 2.1
private final double diff_poly_overhang; // 3.4
private final double diff_contact_overhang; // 6.2 6.2b
private final double thick_overhang = 4;
private final double poly_width = 2; // 3.1
private final double poly_endcap; // 3.3
private final double poly_diff_spacing = 1; // 3.5
private final double gate_length = poly_width; // 3.1
private final double gate_width = diff_width; // 2.1
private final double gate_contact_spacing = 2; // 5.4
private final double poly2_width; // 11.1
private final double contact_size = 2; // 5.1
private final double contact_spacing; // 5.3
private final double contact_array_spacing; // 5.3
private final double contact_metal_overhang_all_sides = 1; // 7.3
private final double contact_poly_overhang; // 5.2 5.2b
private final double nplus_overhang_diff = 2; // 4.2
private final double pplus_overhang_diff = 2; // 4.2
private final double well_width;
private final double nwell_overhang_diff_p; // 2.3
private final double nwell_overhang_diff_n = 3; // 2.4
private final double[] metal_width; // 7.1 9.1 15.1 22.1 26.1 30.1
private final double[] via_size; // 8.1 14.1 21.1 25.1 29.1
private final double[] via_inline_spacing; // 8.2 14.2 21.2 25.2 29.2
private final double[] via_array_spacing; // 8.2 14.2 21.2 25.2 29.2
private final double[] via_overhang; // 8.3 14.3 21.3 25.3 29.3 30.3
ResizeData(int ruleSet, int numMetals, boolean alternateContactRules) {
switch (ruleSet) {
case SUBMRULES:
diff_poly_overhang = 3;
poly_endcap = 2;
poly2_width = 7;
contact_spacing = 3;
well_width = 12;
nwell_overhang_diff_p = 6;
switch (numMetals) {
case 2:
metal_width = new double[]{3, 3, 0, 0, 0, 5};
via_size = new double[]{2, 2, 2, 2, 3};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1};
break;
case 3:
metal_width = new double[]{3, 3, 5, 0, 0, 5};
via_size = new double[]{2, 2, 2, 2, 3};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 2};
break;
case 4:
metal_width = new double[]{3, 3, 3, 6, 0, 5};
via_size = new double[]{2, 2, 2, 2, 3};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 2};
break;
case 5:
metal_width = new double[]{3, 3, 3, 3, 4, 5};
via_size = new double[]{2, 2, 2, 2, 3};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 1, 1};
break;
case 6:
metal_width = new double[]{3, 3, 3, 3, 3, 5};
via_size = new double[]{2, 2, 2, 2, 3};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 1, 1, 1};
break;
default:
throw new IllegalArgumentException("Illegal number of metals " + numMetals + " in SUB rule set");
}
break;
case DEEPRULES:
diff_poly_overhang = 4;
poly_endcap = 2.5;
poly2_width = 0;
contact_spacing = 4;
well_width = 12;
nwell_overhang_diff_p = 6;
switch (numMetals) {
case 5:
metal_width = new double[]{3, 3, 3, 3, 4, 5};
via_size = new double[]{3, 3, 3, 3, 4};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 1, 2};
break;
case 6:
metal_width = new double[]{3, 3, 3, 3, 3, 5};
via_size = new double[]{3, 3, 3, 3, 4};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 1, 1, 2};
break;
default:
throw new IllegalArgumentException("Illegal number of metals " + numMetals + " in DEEP rule set");
}
break;
case SCMOSRULES:
diff_poly_overhang = 3;
poly_endcap = 2;
poly2_width = 3;
contact_spacing = 2;
well_width = 10;
nwell_overhang_diff_p = 5;
switch (numMetals) {
case 2:
metal_width = new double[]{3, 3, 0, 0, 0, 5};
via_size = new double[]{2, 2, 2, 0, 0};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1};
break;
case 3:
metal_width = new double[]{3, 3, 6, 0, 0, 5};
via_size = new double[]{2, 2, 2, 0, 0};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 2};
break;
case 4:
metal_width = new double[]{3, 3, 3, 6, 0, 5};
via_size = new double[]{2, 2, 2, 0, 0};
via_inline_spacing = new double[]{3, 3, 3, 3, 4};
via_overhang = new double[]{1, 1, 1, 2};
break;
default:
throw new IllegalArgumentException("Illegal number of metals " + numMetals + " in SCMOS rule set");
}
break;
default:
throw new AssertionError("Illegal rule set " + ruleSet);
}
diff_contact_overhang = alternateContactRules ? 1 : 1.5;
contact_poly_overhang = alternateContactRules ? 1 : 1.5;
contact_array_spacing = contact_spacing;
via_array_spacing = via_inline_spacing;
}
}
/******************** OVERRIDES ********************/
@Override
protected Map checkParamValues(Map paramValues) {
LinkedHashMap fixedParamValues = new LinkedHashMap();
for (TechFactory.Param param : techFactory.getTechParams()) {
Object value = paramValues.get(param);
if (value == null || value.getClass() != param.factoryValue.getClass()) {
value = param.factoryValue;
}
fixedParamValues.put(param, value);
}
int ruleSet = ((Integer) fixedParamValues.get(techParamRuleSet)).intValue();
int numMetals = ((Integer) fixedParamValues.get(techParamNumMetalLayers)).intValue();
if (ruleSet < SCMOSRULES || ruleSet > DEEPRULES) {
ruleSet = SUBMRULES;
fixedParamValues.put(techParamRuleSet, ruleSet);
}
int minNumMetals, maxNumMetals;
switch (ruleSet) {
case SCMOSRULES:
minNumMetals = 2;
maxNumMetals = 4;
break;
case SUBMRULES:
minNumMetals = 2;
maxNumMetals = 6;
break;
case DEEPRULES:
minNumMetals = 5;
maxNumMetals = 6;
break;
default:
throw new AssertionError();
}
if (numMetals < minNumMetals || numMetals > maxNumMetals) {
numMetals = Math.min(Math.max(numMetals, minNumMetals), maxNumMetals);
fixedParamValues.put(techParamNumMetalLayers, numMetals);
}
return super.checkParamValues(fixedParamValues);
}
/**
* Method to convert old primitive port names to their proper PortProtos.
* @param portName the unknown port name, read from an old Library.
* @param np the PrimitiveNode on which this port resides.
* @return the proper PrimitivePort to use for this name.
*/
@Override
public PrimitivePort convertOldPortName(String portName, PrimitiveNode np) {
String[] transistorPorts = {"poly-left", "diff-top", "poly-right", "diff-bottom"};
for (int i = 0; i < transistorPorts.length; i++) {
if (portName.endsWith(transistorPorts[i])) {
return (PrimitivePort) np.findPortProto(transistorPorts[i]);
}
}
return super.convertOldPortName(portName, np);
}
// /**
// * Method to set the size of a transistor NodeInst in this Technology.
// * Override because for MOCMOS sense of "width" and "length" are
// * different for resistors and transistors.
// * @param ni the NodeInst
// * @param width the new width (positive values only)
// * @param length the new length (positive values only)
// */
// //@Override
// public void setPrimitiveNodeSize(NodeInst ni, double width, double length)
// {
// if (ni.getFunction().isResistor()) {
// super.setPrimitiveNodeSize(ni, length, width);
// } else {
// super.setPrimitiveNodeSize(ni, width, length);
// }
// }
/**
* Method to calculate extension of the poly gate from active layer or of the active from the poly gate.
* @param primNode
* @param poly true to calculate the poly extension
* @param rules
* @return value of the extension
*/
// private double getTransistorExtension(PrimitiveNode primNode, boolean poly, DRCRules rules)
// {
// if (rules == null)
// rules = DRC.getRules(this);
// if (!primNode.getFunction().isTransistor()) return 0.0;
//
// Technology.NodeLayer activeNode = primNode.getNodeLayers()[0]; // active
// Technology.NodeLayer polyCNode;
//
// if (scalableTransistorNodes != null && (primNode == scalableTransistorNodes[P_TYPE] || primNode == scalableTransistorNodes[N_TYPE]))
// {
// polyCNode = primNode.getNodeLayers()[SCALABLE_POLY]; // poly center
// }
// else
// {
// // Standard transistors
// polyCNode = primNode.getElectricalLayers()[2]; // poly center
// }
// DRCTemplate overhang = (poly) ?
// rules.getExtensionRule(polyCNode.getLayer(), activeNode.getLayer(), false) :
// rules.getExtensionRule(activeNode.getLayer(), polyCNode.getLayer(), false);
// return (overhang != null ? overhang.getValue(0) : 0.0);
// }
/** Return a substrate PortInst for this transistor NodeInst
* @param ni the NodeInst
* @return a PortInst for the substrate contact of the transistor
*/
@Override
public PortInst getTransistorBiasPort(NodeInst ni) {
return ni.getPortInst(4);
}
}