/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: LENetlister1.java * Written by Jonathan Gainsley, Sun Microsystems. * * 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. * * Created on November 11, 2003, 3:56 PM */ package com.sun.electric.tool.logicaleffort; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.HierarchyEnumerator; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.variable.VarContext; import com.sun.electric.database.variable.Variable; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.Technology; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.Job; import com.sun.electric.tool.Tool; import com.sun.electric.tool.logicaleffort.LENetlister.NetlisterConstants; import com.sun.electric.tool.user.ErrorLogger; import com.sun.electric.util.TextUtils; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Creates a logical effort netlist to be sized by LESizer. * This is so the LESizer is independent of Electric's Database, * and can match George Chen's C++ version being developed for * PNP. * * @author gainsley */ public class LENetlister1 extends LENetlister { // ALL GATES SAME DELAY /** Netlister constants */ protected NetlisterConstants constants; /** all networks */ private HashMap<String,Net> allNets; /** all instances (LEGATES, not loads) */ private Map<String,Instance> allInstances; /** Sizer */ private LESizer sizer; /** Job we are part of */ private Job job; /** Where to direct output */ private PrintStream out; /** Mapping between NodeInst and Instance */private List<Instance> instancesMap; /** True if we got aborted */ private boolean aborted; /** for logging errors */ private ErrorLogger errorLogger; /** record definition errors so no multiple warnings */ private HashMap<Export,Export> lePortError; /** The top level cell netlisted */ private Cell topLevelCell; private static final boolean DEBUG = false; /** Creates a new instance of LENetlister */ public LENetlister1(Job job, Technology layoutTech) { super(layoutTech); // get preferences for this package Tool leTool = Tool.findTool("logical effort"); constants = null; topLevelCell = null; allNets = new HashMap<String,Net>(); allInstances = new TreeMap/*HashMap*/<String,Instance>(); this.job = job; this.instancesMap = new ArrayList<Instance>(); this.lePortError = new HashMap<Export,Export>(); this.out = new PrintStream((OutputStream)System.out); errorLogger = null; aborted = false; } // Entry point: This netlists the cell @Override public boolean netlist(Cell cell, VarContext context, boolean useCaching) { //ArrayList connectedPorts = new ArrayList(); //connectedPorts.add(Schematics.tech.resistorNode.getPortsList()); assert errorLogger == null; // if (errorLogger != null) errorLogger.delete(); errorLogger = ErrorLogger.newInstance("LE Netlister"); // Netlist netlist = cell.getNetlist(true); // read schematic-specific sizing options constants = getSettings(cell); if (constants == null) { constants = new NetlisterConstants(layoutTech); if (!saveSettings(constants, cell)) { // couldn't save settings to cell, abort return false; } } topLevelCell = cell; HierarchyEnumerator.enumerateCell(cell, context, this, SHORT_RESISTORS); // HierarchyEnumerator.enumerateCell(cell, context, netlist, this); if (aborted) return false; return true; } /** * Size the netlist. * @return true on success, false otherwise. */ public boolean size(LESizer.Alg algorithm) { //lesizer.printDesign(); boolean verbose = false; // create a new sizer sizer = new LESizer(algorithm, this, job, errorLogger); boolean success = sizer.optimizeLoops(constants.epsilon, constants.maxIterations, verbose, constants.alpha, constants.keeperRatio); //out.println("---------After optimization:------------"); //lesizer.printDesign(); // get rid of the sizer sizer = null; return success; } public void getSizes(List<Float> sizes, List<String> varNames, List<NodeInst> nodes, List<VarContext> contexts) { // iterator over all LEGATEs Set<Map.Entry<String,Instance>> allEntries = allInstances.entrySet(); for (Map.Entry<String,Instance> entry : allEntries) { Instance inst = (Instance)entry.getValue(); Nodable no = inst.getNodable(); NodeInst ni = no.getNodeInst(); if (ni != null) no = ni; if (!inst.isLeGate()) continue; String varName = "LEDRIVE_" + inst.getName(); //no.newVar(varName, new Float(inst.getLeX())); //topLevelCell.newVar(varName, new Float(inst.getLeX())); sizes.add(new Float(inst.getLeX())); varNames.add(varName); nodes.add(ni); contexts.add(inst.getContext()); } } public void done() { errorLogger.termLogging(true); //errorLogger = null; } public ErrorLogger getErrorLogger() { return errorLogger; } public void nullErrorLogger() { errorLogger = null; } public NetlisterConstants getConstants() { return constants; } /** * Add new instance to design * @param name name of the instance * param leGate true if this is an LEGate * @param leX size * @param pins list of pins on instance * * @return the new instance added, null if error */ protected Instance addInstance(String name, Instance.Type type, float leSU, float leX, ArrayList<Pin> pins, Nodable no) { if (allInstances.containsKey(name)) { out.println("Error: Instance "+name+" already exists."); return null; } // create instance Instance instance = new Instance(name, type, leSU, leX, no); // create each net if necessary, from pin. Iterator<Pin> iter = pins.iterator(); while (iter.hasNext()) { Pin pin = iter.next(); String netname = pin.getNetName(); // check to see if net had already been added to the design Net net = allNets.get(netname); if (net != null) { pin.setNet(net); pin.setInstance(instance); net.addPin(pin); } else { // create new net net = new Net(netname); allNets.put(netname, net); pin.setNet(net); pin.setInstance(instance); net.addPin(pin); } } instance.setPins(pins); allInstances.put(name, instance); return instance; } //public HashMap getInstancesMap() { return instancesMap; } protected Map<String,Instance> getAllInstances() { return allInstances; } protected HashMap<String,Net> getAllNets() { return allNets; } /** return number of gates sized */ protected int getNumGates() { return allInstances.size(); } protected LESizer getSizer() { return sizer; } protected float getKeeperRatio() { return constants.keeperRatio; } // ======================= Hierarchy Enumerator ============================== /** * Override the default Cell info to pass along logical effort specific information * @return a LECellInfo */ public HierarchyEnumerator.CellInfo newCellInfo() { return new LECellInfo(); } /** * Enter cell initializes the LECellInfo. * @param info the LECellInfo * @return true to process the cell, false to ignore. */ public boolean enterCell(HierarchyEnumerator.CellInfo info) { if (aborted) return false; if (((LETool.AnalyzeCell)job).checkAbort(null)) { aborted = true; return false; } LECellInfo leinfo = (LECellInfo)info; leinfo.leInit(constants); // check if conflicting settings if (topLevelCell != info.getCell()) { if (isSettingsConflict(leinfo.getSettings(), topLevelCell, info.getContext(), info.getCell())) { aborted = true; return false; } } return true; } /** * Visit NodeInst creates a new Logical Effort instance from the * parameters found on the Nodable, if that Nodable is an LEGATE. * It also creates instances for wire models (LEWIREs). * @param ni the Nodable being visited * @param info the cell info * @return true to push down into the Nodable, false to continue. */ public boolean visitNodeInst(Nodable ni, HierarchyEnumerator.CellInfo info) { float leX = (float)0.0; boolean wire = false; boolean primitiveTransistor = false; float x1inverter_totalgate = constants.x1inverter_nwidth + constants.x1inverter_pwidth; // Check if this NodeInst is tagged as a logical effort node Instance.Type type = null; Variable var = null; if ((var = getVar(ni, ATTR_LEGATE)) != null) { // assume it is LEGATE if can't resolve value int gate = VarContext.objectToInt(info.getContext().evalVar(var), 1); if (gate == 1) type = Instance.Type.LEGATE; else return true; } else if ((var = getVar(ni, ATTR_LEKEEPER)) != null) { // assume it is LEKEEPER if can't resolve value int gate = VarContext.objectToInt(info.getContext().evalVar(var), 1); if (gate == 1) type = Instance.Type.LEKEEPER; else return true; } else if (getVar(ni, ATTR_LEWIRE) != null) { type = Instance.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 = ni.getParameterOrVariable(ATTR_LEWIRECAP); float cap = 0; if (var != null) { cap = VarContext.objectToFloat(info.getContext().evalVar(var), 0.0f); } else { var = ni.getParameterOrVariable(ATTR_L); if (var == null) { System.out.println("Error, no L attribute found on LEWIRE "+info.getContext().push(ni).getInstPath(".")); } float len = VarContext.objectToFloat(info.getContext().evalVar(var), 0.0f); var = ni.getParameterOrVariable(Schematics.ATTR_WIDTH); if (var == null) { System.out.println("Warning, no width attribute found on LEWIRE "+info.getContext().push(ni).getInstPath(".")); } float width = VarContext.objectToFloat(info.getContext().evalVar(var), 3.0f); cap = (float)(0.95f*len + 0.05f*len*(width/3.0f)); // capacitance } leX = cap*constants.wireRatio/x1inverter_totalgate; // drive strength X=1 is x1inverter_totalgate lambda of gate wire = true; } else if ((ni.getProto() != null) && (ni.getProto().getFunction().isTransistor())) { // handle transistor loads type = Instance.Type.STATICGATE; var = ni.getParameterOrVariable(Schematics.ATTR_WIDTH); if (var == null) { System.out.println("Error: transistor "+ni+" has no width in Cell "+info.getCell()); errorLogger.logError("Error: transistor "+ni+" has no width in Cell "+info.getCell(), ni.getNodeInst(), info.getCell(), info.getContext(), 0); return false; } float width = VarContext.objectToFloat(info.getContext().evalVar(var), (float)3.0); // note that LE will handle any gate load bloat due to increased gate length leX = (float)(width/x1inverter_totalgate); primitiveTransistor = true; } else if ((ni.getProto() != null) && (ni.getProto().getFunction().isCapacitor())) { type = Instance.Type.CAPACITOR; var = ni.getVar(Schematics.SCHEM_CAPACITANCE); if (var == null) { System.out.println("Error: capacitor "+ni+" has no capacitance in Cell "+ni.getParent()); //errorLogger.logError("Error: capacitor "+no+" has no capacitance in Cell "+info.getCell(), ni.getNodeInst(), true, no.getParent(), context, 0); return false; } float cap = VarContext.objectToFloat(info.getContext().evalVar(var), (float)0.0); leX = (float)(cap/constants.gateCap/1e-15/x1inverter_totalgate); } else if (ni.getParameterOrVariable(ATTR_LESETTINGS) != null) return false; else if (ni.getParameterOrVariable(ATTR_LEIGNORE) != null) return false; if (type == null) return true; // descend into and process if (DEBUG) System.out.println("------------------------------------"); // If got to this point, this is either an LEGATE or an LEWIRE // Both require us to build an instance. ArrayList<Pin> pins = new ArrayList<Pin>(); Netlist netlist = info.getNetlist(); for (Iterator<PortProto> ppIt = ni.getProto().getPorts(); ppIt.hasNext();) { PortProto pp = ppIt.next(); // Note default 'le' value should be one float le = getLE(ni, type, pp, info); String netName = info.getUniqueNetName(info.getNetID(netlist.getNetwork(ni,pp,0)), "."); Pin.Dir dir = Pin.Dir.INPUT; // if it's not an output, it doesn't really matter what it is. if (pp.getCharacteristic() == PortCharacteristic.OUT) dir = Pin.Dir.OUTPUT; if (primitiveTransistor) { // primitive Electric Transistors have their source and drain set to BIDIR, we // want them set to OUTPUT so that they count as diffusion capacitance if (pp.getCharacteristic() == PortCharacteristic.BIDIR) dir = Pin.Dir.OUTPUT; } if (dir == Pin.Dir.INPUT && type == Instance.Type.STATICGATE) { // gate load: check if length > 2, if so, increase LE to account for added capacitance var = ni.getParameterOrVariable(Schematics.ATTR_LENGTH); if (var == null) { System.out.println("Error: transistor "+ni+" has no length in Cell "+info.getCell()); errorLogger.logError("Error: transistor "+ni+" has no length in Cell "+info.getCell(), ni.getNodeInst(), info.getCell(), info.getContext(), 0); } float length = VarContext.objectToFloat(info.getContext().evalVar(var), (float)2.0); // not exactly correct because assumes all cap is area cap, which it isn't if (length != constants.x1inverter_length) le = le * length / constants.x1inverter_length; } pins.add(new Pin(pp.getName(), dir, le, netName)); if (DEBUG) System.out.println(" Added "+dir+" pin "+pp.getName()+", le: "+le+", netName: "+netName+", Network: "+netlist.getNetwork(ni,pp,0)); if (type == Instance.Type.WIRE) break; // this is LEWIRE, only add one pin of it } // see if passed-down step-up exists float localsu = constants.su; if (((LECellInfo)info).getSU() != -1f) localsu = ((LECellInfo)info).getSU(); // check for step-up on gate var = ni.getParameterOrVariable(ATTR_su); if (var != null) { float nisu = VarContext.objectToFloat(info.getContext().evalVar(var), -1f); if (nisu != -1f) localsu = nisu; } // create new leGate instance VarContext vc = info.getContext().push(ni); // to create unique flat name Instance inst = addInstance(vc.getInstPath("."), type, localsu, leX, pins, ni); inst.setContext(info.getContext()); // set instance parameters for sizeable gates if (type == Instance.Type.LEGATE || type == Instance.Type.LEKEEPER) { var = ni.getParameterOrVariable(ATTR_LEPARALLGRP); if (var != null) { // set parallel group number int g = VarContext.objectToInt(info.getContext().evalVar(var), 0); inst.setParallelGroup(g); } } // set mfactor float parentM = ((LECellInfo)info).getMFactor(); inst.setMfactor(parentM); var = LETool.getMFactor(ni); if (var != null) { // set mfactor float m = VarContext.objectToFloat(info.getContext().evalVar(var), 1.0f); m = m * parentM; inst.setMfactor(m); } if (DEBUG) { if (wire) System.out.println(" Added LEWire "+vc.getInstPath(".")+", X="+leX); else System.out.println(" Added instance "+vc.getInstPath(".")+" of type "+type+", X="+leX); } instancesMap.add(inst); return false; } private float getLE(Nodable ni, Instance.Type type, PortProto pp, HierarchyEnumerator.CellInfo info) { boolean leFound = false; // Note default 'le' value should be one float le = 1.0f; if (!(pp instanceof Export)) return le; Variable var = ((Export)pp).getParameterOrVariable(ATTR_le); if (var != null) { leFound = true; le = VarContext.objectToFloat(info.getContext().evalVar(var), 1.0f); } else if ((pp.getCharacteristic() == PortCharacteristic.OUT) && (type == Instance.Type.LEGATE || type == Instance.Type.LEKEEPER)) { // if this is an Sizeable gate's output, look for diffn and diffp float diff = 0; var = ((Export)pp).getParameterOrVariable(ATTR_diffn); if (var != null) { diff += VarContext.objectToFloat(info.getContext().evalVar(var), 0); leFound = true; } var = ((Export)pp).getParameterOrVariable(ATTR_diffp); if (var != null) { diff += VarContext.objectToFloat(info.getContext().evalVar(var), 0); leFound = true; } le = diff/3.0f; } if (!leFound && (type == Instance.Type.LEGATE || type == Instance.Type.LEKEEPER)) { Cell cell = (Cell)ni.getProto(); Export exp = cell.findExport(pp.getName()); if (exp != null && lePortError.get(exp) == null) { String msg = "Warning: Sizeable gate has no logical effort specified for port "+pp.getName()+" in "+cell; System.out.println(msg); errorLogger.logWarning(msg, exp, cell, info.getContext().push(ni), 0); lePortError.put(exp, exp); } } return le; } private Variable getVar(Nodable no, Variable.Key key) { Variable var = no.getParameter(key); //if (var == null) var = no.getVarDefaultOwner().getVar(key); return var; } public void doneVisitNodeInst(Nodable ni, HierarchyEnumerator.CellInfo info) {} /** * Nothing to do for exitCell */ public void exitCell(HierarchyEnumerator.CellInfo info) { } /** * Logical Effort Cell Info class. Keeps track of: * <p>- M factors */ public class LECellInfo extends LENetlister.LECellInfo { } // =============================== Statistics ================================== public void printStatistics() { Collection<Instance> instances = getAllInstances().values(); float totalsize = 0f; float instsize = 0f; int numLEGates = 0; int numLEWires = 0; for (Instance inst : instances) { totalsize += inst.getLeX(); if (inst.getType() == Instance.Type.LEGATE || inst.getType() == Instance.Type.LEKEEPER) { numLEGates++; instsize += inst.getLeX(); } if (inst.getType() == Instance.Type.WIRE) numLEWires++; } System.out.println("Number of LEGATEs: "+numLEGates); System.out.println("Number of Wires: "+numLEWires); System.out.println("Total size of all LEGATEs: "+instsize); System.out.println("Total size of all instances (sized and loads): "+totalsize); } public float getTotalLESize() { return getTotalSize(Instance.Type.LEGATE) + getTotalSize(Instance.Type.LEKEEPER); } /** * return total size of all instances of the specified type * if type is null, uses all types */ public float getTotalSize(Instance.Type type) { Collection<Instance> instances = getAllInstances().values(); float totalsize = 0f; for (Instance inst : instances) { if (type == null) totalsize += inst.getLeX(); else if (inst.getType() == type) totalsize += inst.getLeX(); } return totalsize; } public boolean printResults(Nodable no, VarContext context) { // if this is a NodeInst, convert to Nodable if (no instanceof NodeInst) { no = Netlist.getNodableFor((NodeInst)no, 0); } Instance inst = null; for (Instance instance : instancesMap) { if (instance.getNodable() == no) { if (instance.getContext().getInstPath(".").equals(context.getInstPath("."))) { inst = instance; break; } } } if (inst == null) return false; // failed // MessagesWindow msgs = TopLevel.getMessagesWindow(); //Font oldFont = msgs.getFont(); //msgs.setFont(new Font("Courier", Font.BOLD, oldFont.getSize())); // print netlister info System.out.println("Netlister: Gate Cap="+constants.gateCap+", Alpha="+constants.alpha); // print instance info inst.print(); // collect info about what is driven Pin out = inst.getOutputPins().get(0); Net net = out.getNet(); ArrayList<Pin> gatesDrivenPins = new ArrayList<Pin>(); ArrayList<Pin> loadsDrivenPins = new ArrayList<Pin>(); ArrayList<Pin> wiresDrivenPins = new ArrayList<Pin>(); ArrayList<Pin> gatesFightingPins = new ArrayList<Pin>(); for (Pin pin : net.getAllPins()) { Instance in = pin.getInstance(); if (pin.getDir() == Pin.Dir.INPUT) { if (in.isGate()) gatesDrivenPins.add(pin); //if (in.getType() == Instance.Type.STATICGATE) staticGatesDriven.add(in); if (in.getType() == Instance.Type.LOAD) loadsDrivenPins.add(pin); if (in.getType() == Instance.Type.CAPACITOR) loadsDrivenPins.add(pin); if (in.getType() == Instance.Type.WIRE) wiresDrivenPins.add(pin); } if (pin.getDir() == Pin.Dir.OUTPUT) { if (in.isGate()) gatesFightingPins.add(pin); } } System.out.println("Note: Load = Size * LE * M"); System.out.println("Note: Load = Size * LE * M * Alpha, for Gates Fighting"); float totalLoad = 0f; System.out.println(" -------------------- Gates Driven ("+gatesDrivenPins.size()+") --------------------"); for (Pin pin : gatesDrivenPins) { totalLoad += pin.getInstance().printLoadInfo(pin, constants.alpha); } System.out.println(" -------------------- Loads Driven ("+loadsDrivenPins.size()+") --------------------"); for (Pin pin : loadsDrivenPins) { totalLoad += pin.getInstance().printLoadInfo(pin, constants.alpha); } System.out.println(" -------------------- Wires Driven ("+wiresDrivenPins.size()+") --------------------"); for (Pin pin : wiresDrivenPins) { totalLoad += pin.getInstance().printLoadInfo(pin, constants.alpha); } System.out.println(" -------------------- Gates Fighting ("+gatesFightingPins.size()+") --------------------"); for (Pin pin : gatesFightingPins) { totalLoad += pin.getInstance().printLoadInfo(pin, constants.alpha); } System.out.println("*** Total Load: "+TextUtils.formatDouble(totalLoad, 2)); //msgs.setFont(oldFont); return true; } // ---- TEST STUFF ----- REMOVE LATER ---- public static void test1() { LESizer.test1(); } }