/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MoCMOS.java
*
* Copyright (c) 2003 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.technology.technologies;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.TextUtils;
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 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<TechFactory.Param,Object> 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<Layer> 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 copyState(Technology that) {
super.copyState(that);
MoCMOS mocmos = (MoCMOS)that;
paramRuleSet = mocmos.paramRuleSet;
paramNumMetalLayers = mocmos.paramNumMetalLayers;
paramUseSecondPolysilicon = mocmos.paramUseSecondPolysilicon;
paramDisallowStackedVias = mocmos.paramDisallowStackedVias;
paramUseAlternativeActivePolyRules = mocmos.paramUseAlternativeActivePolyRules;
paramAnalog = mocmos.paramAnalog;
}
@Override
protected void dumpExtraProjectSettings(PrintWriter out, Map<Setting,Object> settings) {
printlnSetting(out, settings, getRuleSetSetting());
printlnSetting(out, settings, getSecondPolysiliconSetting());
printlnSetting(out, settings, getDisallowStackedViasSetting());
printlnSetting(out, settings, getAlternateActivePolyRulesSetting());
printlnSetting(out, settings, getAnalogSetting());
}
/******************** SCALABLE TRANSISTOR DESCRIPTION ********************/
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;
/**
* 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 Technologys.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
* @param pn proto of the ImmutableNodeInst in this Technology
* @param primLayers an array of NodeLayer objects to convert to Poly objects.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
*/
@Override
protected void genShapeOfNode(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, Technology.NodeLayer[] primLayers) {
if (pn != scalableTransistorNodes[P_TYPE] && pn != scalableTransistorNodes[N_TYPE]) {
b.genShapeOfNode(n, pn, primLayers, null);
return;
}
genShapeOfNodeScalable(b, n, pn, null, b.isReasonable());
}
/**
* Special getShapeOfNode function for scalable transistors
* @param m
* @param n
* @param pn
* @param context
* @param reasonable
* @return Array of Poly containing layers representing a Scalable Transistor
*/
private void genShapeOfNodeScalable(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, VarContext context, boolean reasonable)
{
// 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: " + b.getCellBackup().toString() + ", " +
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 = pn.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();
double x1 = p1.getX().getAdder();
double y0 = p0.getY().getAdder();
double y1 = p1.getY().getAdder();
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().withAdder(x0)).withY(p0.getY().withAdder(y0));
points[1] = p1.withX(p1.getX().withAdder(x1)).withY(p1.getY().withAdder(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, pn, 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<DRCTemplate> 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<Setting,Object> 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:<BR>
* 0: SCMOS rules<BR>
* 1: Submicron rules (the default)<BR>
* 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:<BR>
* 0: SCMOS rules<BR>
* 1: Submicron rules<BR>
* 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<Setting,Object> 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<Setting,Object> settings = new HashMap<Setting,Object>();
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<TechFactory.Param> 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<TechFactory.Param,Object> 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<Xml.PrimitiveNodeGroup> metal1PolyContactNodes = new ArrayList<Xml.PrimitiveNodeGroup>(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<Xml.PrimitiveNodeGroup> analogElems = new HashSet<Xml.PrimitiveNodeGroup>();
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 halfSize = 0.5*rd.via_size[i] + rd.via_overhang[i + 1];
resizeSquare(via, halfSize, halfSize, halfSize, 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 State newState(Map<TechFactory.Param,Object> paramValues) {
LinkedHashMap<TechFactory.Param,Object> fixedParamValues = new LinkedHashMap<TechFactory.Param,Object>();
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.newState(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);
}
}