/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LENodable.java
* Written by: Jonathan Gainsley, Sun Microsystems.
*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.logicaleffort;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.util.TextUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class LENodable {
/** Type is a typesafe enum class that describes the type of Instance this is */
protected static class Type {
private final String name;
private Type(String name) { this.name = name; }
public String toString() { return name; }
/** NotSizeable */ protected static final Type STATICGATE = new Type("Static Gate");
/** NotSizeable */ protected static final Type LOAD = new Type("Load");
/** NotSizeable */ protected static final Type WIRE = new Type("Wire");
/** LeGate */ protected static final Type LEGATE = new Type("LE Gate");
/** LeKeeper */ protected static final Type LEKEEPER = new Type("LE Keeper");
/** NotSizeable */ protected static final Type TRANSISTOR = new Type("Transistor");
/** NotSizeable */ protected static final Type CAPACITOR = new Type("Capacitor");
/** Cached cell */ protected static final Type CACHEDCELL = new Type("Cached Cell");
/** Ignore */ protected static final Type IGNORE = new Type("LE Ignore");
}
// --------- Definition fields ----------
/** list of pins */ private List<LEPin> pins; // do not point to networks
/** nodable */ private Nodable no;
/** gate type */ private Type type;
/** output Network */ private Network outputNet;
/** mfactor variable */ private Variable mfactorVar;
/** su variable */ private Variable suVar;
/** parallel group # variable */ private Variable parallelGroupVar;
// --------- instance fields ------------
protected VarContext context;
protected LENetwork outputNetwork; // global network
private float mfactor = 1f;
protected float su;
protected float leX;
protected int parallelGroup;
/**
* Create a new LEInstance tied to the Nodable.
* If the type represents a singular instance, i.e. whose properties
* do not change based on it's location in the hierarchy, then
* leContext is the singular (one and only) context.
* Otherwise, leContext is merely the first of many possible contexts.
* @param no the Nodable
*/
public LENodable(Nodable no, Type type, Variable mfactorVar, Variable suVar, Variable parallelGroupVar) {
this.no = no;
this.type = type;
pins = new ArrayList<LEPin>();
this.outputNet = null;
this.mfactorVar = mfactorVar;
this.suVar = suVar;
this.parallelGroupVar = parallelGroupVar;
this.context = VarContext.globalContext;
this.mfactor = 1f;
this.leX = 0f;
}
protected LENodable copy() {
LENodable copy = new LENodable(no, type, mfactorVar, suVar, parallelGroupVar);
for (LEPin pin : pins) {
copy.addPort(pin.getName(), pin.getDir(), pin.getLE(), pin.getNetwork());
}
return copy;
}
/**
* Add a port to this LEInstance
* @param name the name of the port
* @param dir the direction of the port
* @param le the logical effort of the port
*/
protected void addPort(String name, LEPin.Dir dir, float le, Network jnet) {
LEPin pin = new LEPin(name, dir, le, jnet, this);
pins.add(pin);
}
/** Set the output network */
protected void setOutputNet(Network jnet) { outputNet = jnet; }
/** Get the output network */
protected Network getOutputNet() { return outputNet; }
/** Get the nodable */
protected Nodable getNodable() { return no; }
/** Get the type */
protected Type getType() { return type; }
/** Get the pins */
protected List<LEPin> getPins() { return pins; }
float getMfactor() { return mfactor; }
/** Return true if this is a sizeable gate */
protected boolean isLeGate() {
if (type == Type.LEKEEPER || type == Type.LEGATE) return true;
return false;
}
/** True if this is a gate */
protected boolean isGate() {
if (type == Type.LEGATE || type == Type.LEKEEPER || type == Type.STATICGATE)
return true;
return false;
}
/**
* Set the only context of this LENodable. This is used when the nodable is cacheable,
* and remains the same throughout all contexts above the passed context.
* Returns false if provided context is not enough to evaluate all variables properly.
* @param context the context
* @param outputNetwork the global network loading the output
* @param mfactor the parent's mfactor
* @param su the parent's step-up
*/
protected boolean setOnlyContext(VarContext context, LENetwork outputNetwork, float mfactor, float su, LENetlister2.NetlisterConstants constants) {
boolean evalOk = instantiate(this, context, outputNetwork, mfactor, su, constants, true);
//print();
return evalOk;
}
/**
* Factory method to create a copy of this Nodable with the context-relevant info
* evaluated.
* @param context the context
* @param outputNetwork the global network loading the output
* @param mfactor the parent's mfactor
* @param su the parent's step-up
*/
protected LENodable createUniqueInstance(VarContext context, LENetwork outputNetwork, float mfactor, float su, LENetlister.NetlisterConstants constants) {
LENodable instance = new LENodable(no, type, mfactorVar, suVar, parallelGroupVar);
// copy pins
for (LEPin pin : pins) {
instance.addPort(pin.getName(), pin.getDir(), pin.getLE(), pin.getNetwork());
}
instantiate(instance, context, outputNetwork, mfactor, su, constants, false);
return instance;
}
/**
* Fill-in the given LENodable with evalutated instance-specific info for the given context.
* Returns false if there are variables that cannot be evaluated in the given context
* @param instance the LENodable to fill-in
* @param context the context
* @param outputNetwork the global network loading the output
* @param mfactor the parent's mfactor
* @param su the parent's step-up
*/
private boolean instantiate(LENodable instance, VarContext context, LENetwork outputNetwork, float mfactor, float su,
LENetlister2.NetlisterConstants constants, boolean testCachebility) {
instance.outputNetwork = outputNetwork;
boolean evalOk = true;
// default values
instance.context = context;
instance.leX = getLeX(context, constants, testCachebility);
if (instance.leX == -1f) evalOk = false;
instance.mfactor = mfactor;
instance.su = su;
instance.parallelGroup = 0;
// evaluate variables in context, if any
if (parallelGroupVar != null) {
Object retVal = context.evalVar(parallelGroupVar);
if (retVal == null) evalOk = false;
else instance.parallelGroup = VarContext.objectToInt(retVal, instance.parallelGroup);
}
if (suVar != null) {
Object retVal = context.evalVar(suVar);
if (retVal == null) evalOk = false;
else {
float localsu = VarContext.objectToFloat(retVal, -1f);
instance.su = (localsu == -1f) ? instance.su : localsu;
}
}
if (mfactorVar != null) {
Object retVal = context.evalVar(mfactorVar);
if (retVal == null) evalOk = false;
else instance.mfactor *= VarContext.objectToFloat(retVal, 1f);
}
return evalOk;
}
/**
* Get the leX size for the given LENodable
* Returns -1 if any evaluations failed.
* @param context the VarContext
* @return the leX size, or -1 if eval failed
*/
private float getLeX(VarContext context, LENetlister2.NetlisterConstants constants, boolean testCachebility) {
float leX = (float)0.0;
float x1inverter_totalgate = constants.x1inverter_nwidth + constants.x1inverter_pwidth;
Variable var = null;
Object retVal = null;
if (type == LENodable.Type.WIRE) {
// Note that if inst is an LEWIRE, it will have no 'le' attributes.
// we therefore assign pins to have default 'le' values of one.
// This creates an instance which has Type LEWIRE, but has
// boolean leGate set to false; it will not be sized
// NEW: If we find ATTR_LEWIRECAP, that is the capacitance to use,
// and we will not calculate the cap from L and W.
var = no.getParameterOrVariable(LENetlister.ATTR_LEWIRECAP);
float cap = 0;
if (var != null) {
retVal = context.evalVar(var);
if (testCachebility && (retVal == null)) return -1f;
cap = VarContext.objectToFloat(retVal, 0.0f);
} else {
var = no.getParameterOrVariable(LENetlister.ATTR_L);
if (var == null) {
System.out.println("Error, no L attribute found on LEWIRE "+no.getName()+" in Cell "+no.getParent());
if (testCachebility) return -1f;
}
retVal = context.evalVar(var);
if (testCachebility && (retVal == null)) return -1f;
float len = VarContext.objectToFloat(retVal, 0.0f);
var = no.getParameterOrVariable(Schematics.ATTR_WIDTH);
if (var == null) {
System.out.println("Warning, no width attribute found on LEWIRE "+no.getName()+" in Cell "+no.getParent());
if (testCachebility) return -1f;
}
retVal = context.evalVar(var);
if (testCachebility && (retVal == null)) return -1f;
float width = VarContext.objectToFloat(retVal, 3.0f);
cap = (0.95f*len + 0.05f*len*(width/3.0f));
}
leX = cap*constants.wireRatio; // equivalent lambda of gate
leX = leX/x1inverter_totalgate; // drive strength X=1 is x1inverter_totalgate lambda of gate
}
else if (type == LENodable.Type.TRANSISTOR) {
var = no.getParameterOrVariable(Schematics.ATTR_WIDTH);
if (var == null) {
System.out.println("Error: transistor "+no.getName()+" has no width in Cell "+no.getParent());
//ErrorLogger.ErrorLog log = errorLogger.logError("Error: transistor "+no+" has no width in Cell "+info.getCell(), info.getCell(), 0);
//log.addGeom(ni.getNodeInst(), true, no.getParent(), context);
return -1f;
}
retVal = context.evalVar(var);
if (retVal == null) return -1f;
//float width = VarContext.objectToFloat(retVal, (float)3.0);
float width = VarContext.objectToFloat(retVal, -1f);
if (width == -1f) return -1f;
// var = no.getVar(Schematics.ATTR_LENGTH);
// if (var == null) {
// System.out.println("Error: transistor "+no.getName()+" has no length in Cell "+no.getParent());
// //ErrorLogger.ErrorLog log = errorLogger.logError("Error: transistor "+ni+" has no length in Cell "+info.getCell(), info.getCell(), 0);
// //log.addGeom(ni.getNodeInst(), true, info.getCell(), info.getContext());
// return -1f;
// }
// retVal = context.evalVar(var);
// if (retVal == null) return -1f;
// float length = VarContext.objectToFloat(retVal, (float)2.0);
// not exactly correct because assumes all cap is area cap, which it isn't
leX = (float)(width/x1inverter_totalgate);
}
else if (type == Type.CAPACITOR) {
var = no.getVar(Schematics.SCHEM_CAPACITANCE);
if (var == null) {
System.out.println("Error: capacitor "+no.getName()+" has no capacitance in Cell "+no.getParent());
//ErrorLogger.ErrorLog log = errorLogger.logError("Error: capacitor "+no+" has no capacitance in Cell "+info.getCell(), info.getCell(), 0);
//log.addGeom(ni.getNodeInst(), true, no.getParent(), context);
return -1f;
}
retVal = context.evalVar(var);
if (testCachebility && (retVal == null)) return -1f;
float cap = VarContext.objectToFloat(retVal, (float)0.0);
leX = (float)(cap/constants.gateCap/1e-15/x1inverter_totalgate);
}
return leX;
}
// -----------------------------------------------------------------
protected String getName() {
if (context == null) return no.getName();
return context.push(getNodable()).getInstPath(".");
}
protected void print() {
System.out.println(getType().toString()+": "+getName());
System.out.println(" Size \t= "+leX);
System.out.println(" Step-up \t= "+su);
System.out.println(" Parallel Group\t= "+parallelGroup);
System.out.println(" M Factor\t= "+mfactor);
}
protected String printOneLine(String indent) {
StringBuffer buf = new StringBuffer(indent);
buf.append(getType().toString());
buf.append(": Size="+TextUtils.formatDouble(leX, 2));
//buf.append(" M="+TextUtils.formatDouble(mfactor, 2));
buf.append(" M="+mfactor);
buf.append(" tPG="+parallelGroup);
buf.append(" "+getName());
return buf.toString();
}
protected void printPins() {
for (LEPin pin : pins) {
System.out.println("Pin "+pin.getName()+", le="+pin.getLE()+", dir="+pin.getDir()+" on network "+pin.getNetwork());
}
}
protected float printLoadInfo(LEPin pin, float alpha) {
StringBuffer buf = new StringBuffer();
buf.append(getType().toString());
buf.append("\tSize="+TextUtils.formatDouble(leX, 2));
buf.append("\tLE="+TextUtils.formatDouble(pin.getLE(), 2));
buf.append("\tM="+TextUtils.formatDouble(mfactor, 2));
float load;
if (pin.getDir() == LEPin.Dir.OUTPUT) {
load = (float)(leX*pin.getLE()*mfactor*alpha);
buf.append("\tAlpha="+alpha);
buf.append("\tLoad="+TextUtils.formatDouble(load, 2));
} else {
load = (float)(leX*pin.getLE()*mfactor);
buf.append("\tLoad="+TextUtils.formatDouble(load, 2));
}
buf.append("\t"+getName());
System.out.println(buf.toString());
return load;
}
}