/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: CachedCell.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.Cell;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class CachedCell {
/** source cell */ private Cell cell;
/** map of Nodable to LENodable */ private Map<Nodable,LENodable> lenodables;
/** map of CachedCell instances */ private Map<Nodable,CellNodable> cellnodables; // key: Nodable, Object: CellNodable
/** this cell or subcells contains le gates */ private boolean containsSizableGates;
/** local networks */ private Map<Network,LENetwork> localNetworks; // key: Network, Object: LENetwork
/** if this cell's nodes and subcell's nodes can be fully evaluated as if this cell was the top level */
private Boolean contextFree;
/** list of all cached nodables */ //private List allCachedNodables;
private static final boolean DEBUG = false;
protected static class CellNodable {
Nodable no;
CachedCell subCell;
Variable mfactorVar;
}
protected CachedCell(Cell cell, Netlist netlist) {
this.cell = cell;
lenodables = new HashMap<Nodable,LENodable>();
localNetworks = new HashMap<Network,LENetwork>();
cellnodables = new HashMap<Nodable,CellNodable>();
//allCachedNodables = new ArrayList();
containsSizableGates = false;
contextFree = null;
if (netlist != null) {
// populate local networks
for (Iterator<Network> it = netlist.getNetworks(); it.hasNext(); ) {
Network jnet = (Network)it.next();
LENetwork net = new LENetwork(jnet.describe(false));
if (localNetworks.containsKey(jnet))
System.out.println("Possible hashmap conflict in localNetworks!");
localNetworks.put(jnet, net);
}
}
}
protected boolean isContainsSizableGates() { return containsSizableGates; }
protected LENodable getLENodable(Nodable no) { return lenodables.get(no); }
protected Iterator getLENodables() { return lenodables.values().iterator(); }
protected CellNodable getCellNodable(Nodable no) { return cellnodables.get(no); }
protected Iterator getCellNodables() { return cellnodables.values().iterator(); }
protected Map<Network,LENetwork> getLocalNetworks() { return localNetworks; }
//protected List getAllCachedNodables() { return allCachedNodables; }
/**
* Adds instance of LENodable to this cached cell.
* @param no the corresponding nodable
* @param leno the LENodable
*/
protected void add(Nodable no, LENodable leno) {
if (leno.isLeGate()) containsSizableGates = true;
// hook up gate to local networks
for (Iterator<LEPin> it = leno.getPins().iterator(); it.hasNext(); ) {
LEPin pin = (LEPin)it.next();
Network jnet = pin.getNetwork();
LENetwork net = localNetworks.get(jnet);
/* if (net == null) {
net = new LENetwork(jnet.describe());
localNetworks.put(jnet, net);
}*/
net.add(pin);
}
if (lenodables.containsKey(no))
System.out.println("Possible hash map conflict in lenodables!");
lenodables.put(no, leno);
//allCachedNodables.add(leno);
}
/**
* Adds instance of cached cell "subCell" to this cached cell. This needs to be
* called from Visitor.exitCell of subcell, because it requires subCell's CellInfo.
* @param no the nodable for subcell (in parent)
* @param info the parent info
* @param subCell the subcell cached cell
* @param subCellInfo the subcell CellInfo
*/
protected void add(Nodable no, LENetlister2.LECellInfo info,
CachedCell subCell, LENetlister2.LECellInfo subCellInfo, LENetlister.NetlisterConstants constants) {
CellNodable ceno = new CellNodable();
ceno.no = no;
ceno.subCell = subCell;
ceno.mfactorVar = LETool.getMFactor(no);
if (cellnodables.containsKey(no))
System.out.println("Possible hash map conflict in cellnodables!");
cellnodables.put(no, ceno);
if (subCell.isContainsSizableGates()) {
containsSizableGates = true;
// don't bother caching cells with sizeable gates, they get tossed out later
return;
}
if (!subCell.isContextFree(constants)) {
// if the subcell in not context free, make a copy of it in this cell with
// the context. This cell can be instantiated in some other cell and eventually
// become context free, however then all the instances are tied to that context.
// If they were simply linked, that context could conflict with some context elsewhere
// in the hierarchy where the subcell appears.
subCell = subCell.copy();
ceno.subCell = subCell;
}
//System.out.println("Importing to "+cell.describe()+" from "+no.getName()+":");
// map subCell networks to this cell's networks through global network id's
for (Iterator<Map.Entry<Network,LENetwork>> it = subCell.getLocalNetworks().entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Network,LENetwork> entry = (Map.Entry<Network,LENetwork>)it.next();
Network subJNet = (Network)entry.getKey();
LENetwork subLENet = (LENetwork)entry.getValue();
Network localJNet = subCellInfo.getNetworkInParent(subJNet);
if (localJNet == null) continue;
LENetwork net = localNetworks.get(localJNet);
if (net == null) {
net = new LENetwork(localJNet.describe(false));
localNetworks.put(localJNet, net);
}
net.add(subLENet);
if (DEBUG) {
if (!net.getName().equals("vdd") && !net.getName().equals("gnd")) {
System.out.println(" Added to "+net.getName() +" in "+cell.describe(false)+": "+subLENet.getName()+" from "+subCell.cell.describe(false));
System.out.println(" subcell="+subCell.cell.describe(false)+" subnet="+subLENet.getName()+": ");
subLENet.print();
System.out.println(" result: localcell="+cell.describe(false)+" localnet="+net.getName()+": ");
net.print();
}
}
}
}
protected boolean isContextFree(LENetlister.NetlisterConstants constants) {
if (contextFree == null) {
// this cell has not yet been evaluated, do it now
if (isContainsSizableGates()) {
contextFree = new Boolean(false);
} else {
if (DEBUG) System.out.println("**** Checking if "+cell+" is context free");
boolean cf = isContextFreeRecurse(VarContext.globalContext, 1f, constants);
contextFree = new Boolean(cf);
}
if (DEBUG) System.out.println(">>>> "+cell+" set context free="+contextFree);
}
return contextFree.booleanValue();
}
private boolean isContextFreeRecurse(VarContext context, float mfactor, LENetlister2.NetlisterConstants constants) {
// check LENodables
for (Iterator<LENodable> it = lenodables.values().iterator(); it.hasNext(); ) {
LENodable leno = (LENodable)it.next();
boolean b = leno.setOnlyContext(context, null, mfactor, 0, constants);
if (DEBUG) System.out.println(" gate "+leno.getName()+" cached: "+b+", leX="+leno.leX+", ID="+leno.hashCode());
if (!b) return false;
}
// check cached cell instances
for (Iterator<Map.Entry<Nodable,CellNodable>> it = cellnodables.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Nodable,CellNodable> entry = (Map.Entry<Nodable,CellNodable>)it.next();
Nodable no = (Nodable)entry.getKey();
CellNodable ceno = (CellNodable)entry.getValue();
// see if any mfactor var is evaluatable
float subCellMFactor = mfactor;
if (ceno.mfactorVar != null) {
Object retVal = context.evalVar(ceno.mfactorVar);
if (retVal == null) {
if (DEBUG) System.out.println(" subcell "+ceno.no.getName()+" has Mfactor that cannot be evaluated");
return false;
}
subCellMFactor *= VarContext.objectToFloat(retVal, 1);
}
boolean b = ceno.subCell.isContextFree(constants);
if (b) {
if (DEBUG) System.out.println(" subcell "+ceno.no.getName()+" is context free");
continue;
}
if (!ceno.subCell.isContextFreeRecurse(context.push(no), subCellMFactor, constants)) {
if (DEBUG) System.out.println(" subcell "+ceno.no.getName()+" is NOT recursively context free");
return false;
} else
if (DEBUG) System.out.println(" subcell "+ceno.no.getName()+" is recursively context free");
}
return true;
}
/**
* Create a copy of the cached cell. This also recursively creates
* copies of all subcells (cached cells).
* @return the copy
*/
private CachedCell copy() {
CachedCell copy = new CachedCell(cell, null);
// copy all subcell structures
Map<LENetwork,LENetwork> origSubNetsToCopySubNets = new HashMap<LENetwork,LENetwork>();
for (Iterator<Map.Entry<Nodable,CellNodable>> it = cellnodables.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Nodable,CellNodable> entry = (Map.Entry<Nodable,CellNodable>)it.next();
Nodable no = (Nodable)entry.getKey();
CellNodable ceno = (CellNodable)entry.getValue();
CellNodable cenoCopy = new CellNodable();
cenoCopy.no = ceno.no;
cenoCopy.mfactorVar = ceno.mfactorVar;
cenoCopy.subCell = ceno.subCell.copy();
if (copy.cellnodables.containsKey(no))
System.out.println("Possible hash map conflict in copy.cellnodables!");
copy.cellnodables.put(no, cenoCopy);
// build table of original subnets to copied subnets, so we
// can update subnet links when we copy local networks
for (Iterator<Map.Entry<Network,LENetwork>> nit = ceno.subCell.localNetworks.entrySet().iterator(); nit.hasNext(); ) {
Map.Entry<Network,LENetwork> netentry = (Map.Entry<Network,LENetwork>)nit.next();
Network jnet = (Network)netentry.getKey();
LENetwork origNet = (LENetwork)netentry.getValue();
LENetwork copyNet = cenoCopy.subCell.localNetworks.get(jnet);
origSubNetsToCopySubNets.put(origNet, copyNet);
}
}
// create new networks
// add on subnets, because they are the connectivity to subcells.
for (Iterator<Map.Entry<Network,LENetwork>> it = localNetworks.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Network,LENetwork> entry = (Map.Entry<Network,LENetwork>)it.next();
Network jnet = (Network)entry.getKey();
LENetwork net = (LENetwork)entry.getValue();
LENetwork netCopy = new LENetwork(net.getName());
for (Iterator<LENetwork> nit = net.getSubNets(); nit.hasNext(); ) {
LENetwork subnet = (LENetwork)nit.next();
// find copy of subnet in cellnodables copy
LENetwork copySubNet = origSubNetsToCopySubNets.get(subnet);
netCopy.add(copySubNet);
}
if (copy.localNetworks.containsKey(jnet))
System.out.println("Possible hashmap conflict in copy.localNetworks!");
copy.localNetworks.put(jnet, netCopy);
}
// copy all lenodables: this sets pins of local networks.
for (Iterator<LENodable> it = lenodables.values().iterator(); it.hasNext(); ) {
LENodable leno = (LENodable)it.next();
LENodable lenoCopy = leno.copy();
copy.add(leno.getNodable(), lenoCopy);
}
copy.containsSizableGates = containsSizableGates;
copy.contextFree = contextFree;
//copy.allCachedNodables.addAll(allCachedNodables);
return copy;
}
/**
* Print the contents of the Cached cell
* @param indent
*/
protected void printContents(String indent, PrintStream out) {
out.println(indent+"CachedCell "+cell.describe(true)+" contents:");
for (Iterator<LENodable> it = lenodables.values().iterator(); it.hasNext(); ) {
LENodable leno = (LENodable)it.next();
out.println(leno.printOneLine(indent+" "));
}
for (Iterator<Map.Entry<Network,LENetwork>> it = localNetworks.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Network,LENetwork> entry = (Map.Entry<Network,LENetwork>)it.next();
Network jnet = (Network)entry.getKey();
LENetwork net = (LENetwork)entry.getValue();
net.print(indent+" ", out);
}
for (Iterator<Map.Entry<Nodable,CellNodable>> it = cellnodables.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Nodable,CellNodable> entry = (Map.Entry<Nodable,CellNodable>)it.next();
Nodable no = (Nodable)entry.getKey();
CellNodable ceno = (CellNodable)entry.getValue();
//ceno.subCell.printContents(indent+" ", out);
boolean subCachable = ceno.subCell.isContextFree(null);
System.out.println(indent+indent+"contains subCachedCell for "+ceno.subCell.cell+" ("+
(subCachable?"cachable":"not cachable")+")");
}
}
}