/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Part.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.tool.ncc.netlist;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.sun.electric.technology.PrimitiveNode.Function;
import com.sun.electric.tool.ncc.NccOptions;
import com.sun.electric.tool.ncc.netlist.NccNameProxy.PartNameProxy;
import com.sun.electric.tool.ncc.result.PartReport.PartReportable;
import com.sun.electric.tool.ncc.trees.Circuit;
import com.sun.electric.tool.Job;
/** Part is an intermediate abstract sub-class of NetObject.
* sub-classes of Part include Transistor, Resistor, (Capacitor), but
* NOT Port. */
public abstract class Part extends NetObject implements PartReportable {
// ------------------- constants ------------------
private static final Wire[] DELETED = null;
private static final int NUM_FUNCS = Function.values().length;
protected static final int TYPE_FIELD_WIDTH =
(int) Math.ceil( Math.log(NUM_FUNCS)/Math.log(2) );
// ---------- private data -------------
private PartNameProxy nameProxy;
private final Function type;
protected Wire[] pins;
// ---------- private methods ----------
/** @param name the name of Part
* @param type the type of Parts
* @param pins Wires attached to pins of Part */
protected Part(PartNameProxy name, Function type, Wire[] pins){
nameProxy = name;
this.type = type;
this.pins = pins;
for (int i=0; i<pins.length; i++) pins[i].add(this);
}
// ---------- public methods ----------
/** Return the type of part. The type distinguishes between MOS
* transistors, bipolar transistors, resistors, and subcircuits.
*
* The type also distinguishes variations. For MOS
* transistors it distinguishes between different threshold
* devices, different voltage devices, whether the MOS is a depletion
* transistor, floating gate transistor, etc.
*
* For Resistors the type distinguishes between p-poly vs n-poly vs
* p-well vs n-well resistors.
*
* The type does NOT distinguish between the MOS transistors that
* are stacked in series. The type does NOT distinguish between
* MOS transistors that are wired as capacitors. These distinctions
* are created dynamically.
*
* The type does NOT distinguish between 3 vs 4 pin MOS transistors.
* This distinction isn't important for NCC.
*
* As Electric evolves I expect it will accumulate additional
* variations. I'm trying to write NCC so that it automatically
* accommodates those variations without substantial, if any
* change */
public Function type() {return type;}
@Override public String getName() {return nameProxy.getName();}
@Override public Iterator getConnected() {return Arrays.asList(pins).iterator();}
public PartNameProxy getNameProxy() {return nameProxy;}
@Override public Type getNetObjType() {return Type.PART;}
/** Here is the accessor for the number of terminals on this Part
* @return the number of terminals on this Part, usually a small number. */
public int numPins() {return pins.length;}
/** Here is an accessor method for the coefficient array for this
* Part. The terminal coefficients are used to compute new hash
* codes.
* @return the array of terminal coefficients for this Part*/
public abstract int[] getPinCoeffs();
/** This method attempts to merge this Part in parallel with another Part
* @param p the other Part with which to merge
* @param nccOpt NccOptions. Used for size tolerance specification.
* @return true if merge was successful, false otherwise */
public abstract boolean parallelMerge(Part p, NccOptions nccOpt);
/** Compute a hash code for this part for the purpose of performing
* parallel merge. If two parallel Parts should be merged into one then
* hashCodeForParallelMerge() must return the same value for both
* Parts. */
public abstract Integer hashCodeForParallelMerge();
/** Mark this Part deleted and release all storage */
public void setDeleted() {pins=DELETED;}
@Override public boolean isDeleted() {return pins==DELETED;}
/** Get the number of distinct Wires this part is connected to.
* For example, if all pins are connected to the same Wire then return 1.
* This method is only used for sanity checking by StratCount.
* @return the number of distinct Wires to which this Part is connected */
public int numDistinctWires() {
Set<Wire> wires = new HashSet<Wire>();
for (int i=0; i<pins.length; i++) wires.add(pins[i]);
return wires.size();
}
/** returns String describing Part's type */
public abstract String typeString();
/** returns a unique int value for each distinct Part type */
public abstract int typeCode();
/** How many pins of this Part are connected to Wire.
* @param w the Wire to test
* @return number of pins connected to Wire */
public int numPinsConnected(Wire w) {
int numConnected = 0;
for (int i=0; i<pins.length; i++) {
if (pins[i]==w) numConnected++;
}
return numConnected;
}
public Integer computeHashCode(){
int sum= 0;
int codes[]= getPinCoeffs();
for(int i=0; i<pins.length; i++) {
Wire w = pins[i];
sum += w.getCode() * codes[i];
}
return new Integer(sum);
}
/** The Part must compute a hash code contribution for a Wire to
* use. because the Wire doesn't know how it's connected to this
* Part and multiple connections are allowed.
* @param w the Wire for which a hash code is needed
* @return an int with the code contribution. */
public int getHashFor(Wire w){
int sum= 0;
int codes[]= getPinCoeffs();
for(int i=0; i<pins.length; i++){
Wire x= pins[i];
error(x==null, "null wire?");
if(x==w) sum += codes[i] * getCode();
}
return sum;
}
/** check that this Part is in proper form
* complain if it's wrong */
@Override public void checkMe(Circuit parent){
error(parent!=getParent(), "wrong parent");
for(int i=0; i<pins.length; i++){
Wire w= pins[i];
error(w==null, "Wire is null");
error(!w.touches(this), "Wire not connected to Part");
}
}
/** @return the PinType for the nth pin */
public abstract PinType getPinTypeOfNthPin(int n);
/** @return a String containing the part type, the Cell containing the part,
* and the instance name */
@Override public String instanceDescription() {
// Don't print "Cell instance:" in root Cell where there is no path.
String inst = nameProxy.cellInstPath();
String instMsg = inst.equals("") ? "" : (" Cell instance: "+inst);
return typeString()+" "+nameProxy.leafName()+" in Cell: "+
nameProxy.leafCell().libDescribe()+instMsg;
}
/** Report the numeric values of this Part,
* for example: width, length, resistance.
* @return a String describing the Part's numeric values.*/
@Override public abstract String valueDescription();
/** comma separated list of pins connected to w */
public abstract String connectionDescription(Wire w);
public boolean isMos() {return this instanceof Mos;}
public boolean isResistor() {return this instanceof Resistor;}
public double getWidth() {
Job.error(true, "Part has no width"); return 0;}
public double getLength() {
Job.error(true, "Part has no length"); return 0;}
}