/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: LESizer.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, 4:42 PM */ package com.sun.electric.tool.logicaleffort; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.tool.Job; import com.sun.electric.tool.user.ErrorLogger; import com.sun.electric.tool.util.concurrent.utils.ElapseTimer; import com.sun.electric.util.TextUtils; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * LESizer sizes an LENetlist. The LENetlist is generated by LENetlister from * the Electric database, or perhaps read in from a Spice file(?) * * NOTE: the only 'Electric' objects used are in LENetlister, any objects * referenced in this file are from the logicaleffort package, although their * names may imply otherwise. Their names are as such because their names match * PNP's naming scheme. * * @author gainsley */ public class LESizer { /** which algorithm to use */ private Alg optimizationAlg; /** Where to direct output */ private PrintStream out; /** What job we are part of */ private Job job; /** Netlist */ private LENetlister1 netlist; /** error logger */ private ErrorLogger errorLogger; /** Alg is a typesafe enum class that describes the algorithm to be used */ public static enum Alg { /** Sizes all gates for user specified equal gate delay */ EQUALGATEDELAYS("Equal Gate Delays"), /** Sizes for optimal path delay */ PATHDELAY("Path Delay"); private final String name; private Alg(String name) { this.name = name; } public String toString() { return name; } } /** Creates a new instance of LESizer */ protected LESizer(Alg alg, LENetlister1 netlist, Job job, ErrorLogger errorLogger) { optimizationAlg = alg; this.netlist = netlist; this.job = job; this.errorLogger = errorLogger; out = new PrintStream(System.out); } // ============================ Sizing For Equal Gate Delays // ========================== /** * Optimize using loop algorithm; * * @param maxDeltaX * maximum tolerance allowed in X * @param N * maximum number of loops * @param verbose * print out size information for each optimization loop * @return true if succeeded, false otherwise * * Optimization will stop when the difference in sizes (X) is less * than maxDeltaX, or when N iterations have occurred. */ protected boolean optimizeLoops(float maxDeltaX, int N, boolean verbose, float alpha, float keeperRatio) { // iterate through all the instances, updating sizes float currentLoopDeltaX = maxDeltaX + 1; // force at least one iteration float lastLoopDeltaX = currentLoopDeltaX; int divergingIters = 0; // count number if iterations sizing is // diverging ElapseTimer timer = ElapseTimer.createInstance(); int loopcount = 0; while ((currentLoopDeltaX > maxDeltaX) && (loopcount < N)) { // check for aborted state of job if (((LETool.AnalyzeCell) job).checkAbort(null)) return false; currentLoopDeltaX = 0; timer.start(); System.out.print(" Iteration " + loopcount); if (verbose) System.out.println(":"); // iterate through each instance Iterator<Instance> instancesIter = netlist.getAllInstances().values().iterator(); while (instancesIter.hasNext()) { Instance instance = instancesIter.next(); String instanceName = instance.getName(); // make sure it is a sizeable gate if (instance.isLeGate()) { // get output pin (do not iterate over all output pins, does // not make sense) ArrayList<Pin> outputPins = instance.getOutputPins(); if (outputPins.size() != 1) { // error continue; } Pin outputPin = outputPins.get(0); Net net = outputPin.getNet(); // now find all pins connected to this net ArrayList<Pin> netpins = net.getAllPins(); // find all drivers in same group, of same type (LEGATe or // LEKEEPER) List<Instance> drivers = new ArrayList<Instance>(); List<Instance> arrayedDrivers = new ArrayList<Instance>(); for (Pin pin : netpins) { // only interested in drivers if (pin.getDir() != Pin.Dir.OUTPUT) continue; Instance inst = pin.getInstance(); if (inst.getType() == instance.getType()) { if (inst.getParallelGroup() == instance.getParallelGroup()) { // add the instance. Note this adds the current // instance at some point as well drivers.add(inst); // error check if (inst.getParallelGroup() > 0 && loopcount == 0 && inst.getLeSU() != instance.getLeSU()) { String msg = "\nError: LEGATE \"" + inst.getName() + "\" drives in parallel with \"" + instance.getName() + "\" but has a different step-up"; System.out.println(msg); NodeInst ni = inst.getNodable().getNodeInst(); if (ni != null) { errorLogger.logError(msg, ni, ni.getParent(), inst.getContext(), 0); } } } } if ((inst.getNodable().getNodeInst() == instance.getNodable().getNodeInst()) && (inst.getContext() == instance.getContext())) { // this must be an arrayed driver: not this also // adds current instance at some point as well arrayedDrivers.add(inst); } } // this will be the new size. float newX = 0; // if this is an LEKEEPER, we need to find smallest gate (or // group) // that also drives this net, it is assumed that will have // to overpower this keeper if (instance.getType() == Instance.Type.LEKEEPER) { Map<String, List<Instance>> drivingGroups = new HashMap<String, List<Instance>>(); float smallestX = 0; // iterate over all drivers on net for (Pin pin : netpins) { // only interested in drivers if (pin.getDir() != Pin.Dir.OUTPUT) continue; Instance inst = pin.getInstance(); // if ((inst.getType() == Instance.Type.LEGATE) || // (inst.getType() == Instance.Type.STATICGATE)) { if ((inst.getType() == Instance.Type.LEGATE)) { // organize by groups int i = inst.getParallelGroup(); Integer integer = new Integer(i); if (i <= 0) { // this gate drives independently, check // size if (smallestX == 0) smallestX = inst.getLeX(); if (inst.getLeX() < smallestX) smallestX = inst.getLeX(); } // add to group to sum up drive strength later List<Instance> groupList = drivingGroups.get(integer.toString()); if (groupList == null) { groupList = new ArrayList<Instance>(); drivingGroups.put(integer.toString(), groupList); } groupList.add(inst); } } // find smallest total size of groups Set<String> keys = drivingGroups.keySet(); for (String str : keys) { List<Instance> groupList = drivingGroups.get(str); if (groupList == null) continue; // skip empty groups // get size float sizeX = 0; for (Instance inst : groupList) { sizeX += inst.getLeX(); } // check size of group if (smallestX == 0) smallestX = sizeX; if (sizeX < smallestX) smallestX = sizeX; } // if no drivers found, issue warning if (!keys.iterator().hasNext() && loopcount == 0) { String msg = "\nError: LEKEEPER \"" + instance.getName() + "\" does not fight against any drivers"; System.out.println(msg); NodeInst ni = instance.getNodable().getNodeInst(); if (ni != null) { errorLogger.logError(msg, ni, ni.getParent(), instance.getContext(), 0); } } // For now, split effort equally amongst all drivers if (instance.getParallelGroup() <= 0) { newX = smallestX * netlist.getKeeperRatio() / arrayedDrivers.size(); } else { newX = smallestX * netlist.getKeeperRatio() / drivers.size(); } } // If this is an LEGATE, simply sum all capacitances on the // Net if (instance.getType() == Instance.Type.LEGATE) { // compute total le*X (totalcap) float totalcap = 0; Iterator<Pin> netpinsIter = netpins.iterator(); int numLoads = 0; while (netpinsIter.hasNext()) { Pin netpin = netpinsIter.next(); Instance netpinInstance = netpin.getInstance(); float load = netpinInstance.getLeX() * netpin.getLE() * (float) netpinInstance.getMfactor(); if (netpin.getDir() == Pin.Dir.OUTPUT) load *= alpha; totalcap += load; // check to see if gate is only driving itself if (netpinInstance != instance) numLoads++; } // create error if no loads only on first iteration if (numLoads == 0 && loopcount == 0) { String msg = "\nError: LEGATE \"" + instance.getName() + "\" has no loads: will be ignored"; System.out.println(msg); NodeInst ni = instance.getNodable().getNodeInst(); if (ni != null) { errorLogger.logError(msg, ni, ni.getParent(), instance.getContext(), 1); } } // ignore if no loads, on all iterations if (numLoads == 0) continue; // For now, split effort equally amongst all drivers // Group 0 drives individually if (instance.getParallelGroup() <= 0) { newX = totalcap / instance.getLeSU() / arrayedDrivers.size(); } else { newX = totalcap / instance.getLeSU() / drivers.size(); } // also take into account mfactor of driver newX = newX / (float) instance.getMfactor(); } // determine change in size float currentX = instance.getLeX(); float deltaX; if (currentX == 0 && newX == 0) { // if before and after are 0, delta is 0 deltaX = 0f; } else { // account for divide by 0 if (currentX == 0) currentX = 0.001f; deltaX = Math.abs((newX - currentX) / currentX); } currentLoopDeltaX = (deltaX > currentLoopDeltaX) ? deltaX : currentLoopDeltaX; if (verbose) { out.println("Optimized " + instanceName + ": size: " + TextUtils.formatDouble(instance.getLeX(), 3) + "x ==> " + TextUtils.formatDouble(newX, 3) + "x"); } instance.setLeX(newX); } // if (leGate) } // while (instancesIter) // All done, print some statistics about this iteration timer.end(); System.out.println(" ...done (" + timer + "), delta: " + currentLoopDeltaX); if (verbose) System.out.println("-----------------------------------"); loopcount++; // check to see if we're diverging or not converging if (currentLoopDeltaX >= lastLoopDeltaX) { if (divergingIters > 2) { System.out.println(" Sizing diverging, aborting"); return false; } divergingIters++; } lastLoopDeltaX = currentLoopDeltaX; } // while (currentLoopDeltaX ... ) return true; } // ========================== Sizing for Path Optimization // ===================== protected List getEndNets() { List endNets = new ArrayList(); Iterator<Net> netIter = netlist.getAllNets().values().iterator(); while (netIter.hasNext()) { Net net = netIter.next(); } return null; } // =============================== Statistics // ================================== // ============================== Design Printing // =============================== /** * Dump the design information for debugging purposes */ protected void printDesign() { out.println("Instances in design are:"); Iterator<Instance> instancesIter = netlist.getAllInstances().values().iterator(); while (instancesIter.hasNext()) { Instance instance = instancesIter.next(); String instanceName = instance.getName(); StringBuffer buf = new StringBuffer(); out.println("\t" + instanceName + " ==> " + TextUtils.formatDouble(instance.getLeX(), 3) + "x"); ArrayList<Pin> pins = instance.getAllPins(); // now print out pinname ==> netname Iterator<Pin> pinsIter = pins.iterator(); while (pinsIter.hasNext()) { Pin pin = pinsIter.next(); out.println("\t\t" + pin.getName() + " ==> " + pin.getNetName()); } } } /** * Generate simple size file (for regression purposes) * * @param filename * output filename */ protected int printDesignSizes(String filename) { // open output file try { FileWriter fileWriter = new FileWriter(filename); // throws // IOException // iterate through all instances Iterator<Instance> instancesIter = netlist.getAllInstances().values().iterator(); while (instancesIter.hasNext()) { Instance instance = instancesIter.next(); String instanceName = instance.getName(); float leX = instance.getLeX(); fileWriter.write(instanceName + " " + leX + "\n"); // throws // IOException fileWriter.flush(); // throws IOException } fileWriter.close(); // throws IOException } catch (IOException e) { out.println("Writing to file " + filename + ": " + e.getMessage()); return 1; } return 0; } /** * Generate SKILL backannotation file * * @param filename * output filename * @param libname * The Opus library name to be annotated * @param cellname * The Opus cell to be annotated */ protected int printDesignSkill(String filename, String libname, String cellname) { // nothing here return 0; } /** * Dummy method to improve test coverage */ protected void testcoverage() { // nothing here } // ---------------------------------------TEST--------------------------------------- // ---------------------------------------TEST--------------------------------------- /** run a contrived test */ public static void test1() { System.out.println("Running GASP test circuit"); System.out.println("========================="); float su = (float) 4.0; LENetlister1 netlist = new LENetlister1(null, null); { // inv1 Pin pin_a = new Pin("A", Pin.Dir.INPUT, (float) 1.0, "nand1_out"); Pin pin_y = new Pin("Y", Pin.Dir.OUTPUT, (float) 1.0, "inv1_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_a); pins.add(pin_y); netlist.addInstance("inv1", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // inv2 Pin pin_a = new Pin("A", Pin.Dir.INPUT, (float) 1.0, "pu_out"); Pin pin_y = new Pin("Y", Pin.Dir.OUTPUT, (float) 1.0, "inv2_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_a); pins.add(pin_y); netlist.addInstance("inv2", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // inv3 Pin pin_a = new Pin("A", Pin.Dir.INPUT, (float) 1.0, "nand1_out"); Pin pin_y = new Pin("Y", Pin.Dir.OUTPUT, (float) 1.0, "inv3_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_a); pins.add(pin_y); netlist.addInstance("inv3", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // nand1 Pin pin_a = new Pin("A", Pin.Dir.INPUT, (float) 1.333, "inv2_out"); Pin pin_b = new Pin("B", Pin.Dir.INPUT, (float) 1.333, "pd_out"); Pin pin_y = new Pin("Y", Pin.Dir.OUTPUT, (float) 2.0, "nand1_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_a); pins.add(pin_b); pins.add(pin_y); netlist.addInstance("nand1", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // pu Pin pin_g = new Pin("G", Pin.Dir.INPUT, (float) 0.667, "nand1_out"); Pin pin_d = new Pin("D", Pin.Dir.OUTPUT, (float) 0.667, "pu_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_g); pins.add(pin_d); netlist.addInstance("pu", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // pd Pin pin_g = new Pin("G", Pin.Dir.INPUT, (float) 0.333, "inv3_out"); Pin pin_d = new Pin("D", Pin.Dir.OUTPUT, (float) 0.333, "pd_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_g); pins.add(pin_d); netlist.addInstance("pd", Instance.Type.LEGATE, su, (float) 1.0, pins, null); } { // cap1 Pin pin_c = new Pin("C", Pin.Dir.INPUT, (float) 1.0, "pd_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_c); netlist.addInstance("cap1", Instance.Type.LOAD, su, (float) 0.0, pins, null); } { // cap2 Pin pin_c = new Pin("C", Pin.Dir.INPUT, (float) 1.0, "pu_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_c); netlist.addInstance("cap2", Instance.Type.LOAD, su, (float) 0.0, pins, null); } { // cap3 Pin pin_c = new Pin("C", Pin.Dir.INPUT, (float) 1.0, "inv1_out"); ArrayList<Pin> pins = new ArrayList<Pin>(); pins.add(pin_c); netlist.addInstance("cap3", Instance.Type.LOAD, su, (float) 100.0, pins, null); } netlist.getSizer().printDesign(); netlist.getSizer().optimizeLoops((float) 0.01, 30, true, (float) 0.7, (float) 0.1); System.out.println("After optimization:"); netlist.getSizer().printDesign(); } }