/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LESizer2.java
* Written by: Jonathan Gainsley, Sun Microsystems.
*
* 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.
*
* Created on November 11, 2003, 4:42 PM
*/
package com.sun.electric.tool.logicaleffort;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.user.ErrorLogger;
import java.io.PrintStream;
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 LESizer2 {
/** which algorithm to use */ private LESizer.Alg optimizationAlg;
/** Where to direct output */ private PrintStream out;
/** What job we are part of */ private Job job;
/** Netlist */ private LENetlister2 netlist;
/** error logger */ private ErrorLogger errorLogger;
/** Creates a new instance of LESizer */
protected LESizer2(LESizer.Alg alg, LENetlister2 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
long startTime;
int loopcount = 0;
while ((currentLoopDeltaX > maxDeltaX) && (loopcount < N)) {
// check for aborted state of job
if (((LETool.AnalyzeCell)job).checkAbort(null)) return false;
currentLoopDeltaX = 0;
startTime = System.currentTimeMillis();
System.out.print(" Iteration "+loopcount);
if (verbose) System.out.println(":");
// iterate through each instance
for (Iterator<LENodable> lit = netlist.getSizeableNodables(); lit.hasNext(); ) {
LENodable leno = lit.next();
// ignore it if not a sizeable gate
if (!leno.isLeGate()) continue;
LENetwork outputNet = leno.outputNetwork;
// find all drivers in same group, of same type (LEGATE or LEKEEPER)
List<LENodable> drivers = new ArrayList<LENodable>();
List<LENodable> arrayedDrivers = new ArrayList<LENodable>();
for (LEPin pin : outputNet.getAllPins()) {
// only interested in drivers
if (pin.getDir() != LEPin.Dir.OUTPUT) continue;
LENodable loopLeno = pin.getInstance();
if (leno.getType() == loopLeno.getType()) {
if (leno.parallelGroup == loopLeno.parallelGroup) {
// add the instance. Note this adds the current instance at some point as well
drivers.add(loopLeno);
// error check
if (leno.parallelGroup > 0 && loopcount == 0 && leno.su != loopLeno.su) {
String msg = "\nError: LEGATE \""+leno.getName()+"\" drives in parallel with \""+loopLeno.getName()+
"\" but has a different step-up";
System.out.println(msg);
NodeInst ni = leno.getNodable().getNodeInst();
if (ni != null) {
errorLogger.logError(msg, ni, ni.getParent(), leno.context, 0);
}
}
}
}
if ((loopLeno.getNodable().getNodeInst() == leno.getNodable().getNodeInst()) &&
(loopLeno.context.getInstPath(".").equals(leno.context.getInstPath(".")))) {
// this must be an arrayed driver: not this also adds current instance at some point as well
arrayedDrivers.add(loopLeno);
}
}
// 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 (leno.getType() == LENodable.Type.LEKEEPER) {
Map<String,List<LENodable>> drivingGroups = new HashMap<String,List<LENodable>>();
float smallestX = 0;
// iterate over all drivers on net
for (LEPin pin : outputNet.getAllPins()) {
// only interested in drivers
if (pin.getDir() != LEPin.Dir.OUTPUT) continue;
LENodable loopLeno = pin.getInstance();
if (loopLeno.getType() == LENodable.Type.LEGATE || loopLeno.getType() == LENodable.Type.STATICGATE) {
// organize by groups
int i = loopLeno.parallelGroup;
Integer integer = new Integer(i);
if (i <= 0) {
// this gate drives independently, check size
if (smallestX == 0) smallestX = loopLeno.leX;
if (loopLeno.leX < smallestX) smallestX = loopLeno.leX;
}
// add to group to sum up drive strength later
List<LENodable> groupList = drivingGroups.get(integer.toString());
if (groupList == null) {
groupList = new ArrayList<LENodable>();
drivingGroups.put(integer.toString(), groupList);
}
groupList.add(loopLeno);
}
}
// find smallest total size of groups
Set<String> keys = drivingGroups.keySet();
for (String str : keys) {
List<LENodable> groupList = drivingGroups.get(str);
if (groupList == null) continue; // skip empty groups
// get size
float sizeX = 0;
for (LENodable loopLeno : groupList) {
sizeX += loopLeno.leX;
}
// 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 \""+leno.getName()+"\" does not fight against any drivers";
System.out.println(msg);
NodeInst ni = leno.getNodable().getNodeInst();
if (ni != null) {
errorLogger.logError(msg, ni, ni.getParent(), leno.context, 0);
}
}
// For now, split effort equally amongst all drivers
if (leno.parallelGroup <= 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 (leno.getType() == LENodable.Type.LEGATE) {
// compute total le*X (totalcap)
float totalcap = 0;
int numLoads = 0;
//System.out.println("LENode "+leno.getName()+" drives: ");
//outputNet.print();
for (LEPin pin : outputNet.getAllPins()) {
LENodable loopLeno = pin.getInstance();
float load = loopLeno.leX * pin.getLE() * loopLeno.getMfactor();
if (pin.getDir() == LEPin.Dir.OUTPUT) load *= alpha;
totalcap += load;
// check to see if gate is only driving itself
if (loopLeno != leno)
numLoads++;
}
// create error if no loads only on first iteration
if (numLoads == 0 && loopcount == 0) {
String msg = "\nError: LEGATE \""+leno.getName()+"\" has no loads: will be ignored";
System.out.println(msg);
NodeInst ni = leno.getNodable().getNodeInst();
if (ni != null) {
errorLogger.logError(msg, ni, ni.getParent(), leno.context, 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 (leno.parallelGroup <= 0)
newX = totalcap / leno.su / arrayedDrivers.size();
else {
newX = totalcap / leno.su / drivers.size();
}
// also take into account mfactor of driver
newX = newX / (float)leno.getMfactor();
}
// determine change in size
float currentX = leno.leX;
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 "+leno.getName()+": size: "+
TextUtils.formatDouble(leno.leX, 3)+
"x ==> "+TextUtils.formatDouble(newX, 3)+"x");
}
leno.leX = newX;
}
// All done, print some statistics about this iteration
String elapsed = TextUtils.getElapsedTime(System.currentTimeMillis()-startTime);
System.out.println(" ...done ("+elapsed+"), 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 =====================
// =============================== Statistics ==================================
// ============================== Design Printing ===============================
}