/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: HierarchyInfo.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.processing;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.tool.ncc.basic.CellContext;
import com.sun.electric.tool.ncc.basic.CompareList;
import com.sun.electric.tool.ncc.basic.CompareLists;
import com.sun.electric.tool.Job;
/** Information needed to perform hierarchical netlist comparison.
* NCC usually performs comparisons hierarchically. NCC starts with
* leaf Cells and works towards the root Cells. After NCC checks
* Cells that are lower in the design hierarchy, NCC saves information
* that allows it abstract those cells when it compare Cells
* higher in the design hierarchy. The information necessary to abstract
* lower level cells is stored in HierarchyInfo. */
public class HierarchyInfo {
/** name of the current CompareList (usually CellGroup name) */
private String subcktName;
/** unique int assigned to the current compareList */
private int compareListID=0;
/** the Cells we've added to the current compareList */
private List<Cell> cellsInCompareList = new ArrayList<Cell>();
/** flag indicating that we must remove SubcircuitInfo for all Cells in the
* current Cell Group. */
private boolean purgeCurrentCompareList;
/** information for all Cells in all the compareLists we've encountered
* so far */
private Map<Cell,SubcircuitInfo> cellToSubcktInfo = new HashMap<Cell,SubcircuitInfo>();
private Set<Cell> cellsInSharedCellGroups;
// ----------------------------- public methods ---------------------------
/** You must call this before you begin comparing Cells in a new
* compareList. Then for each Cell in the compareList you must call
* addSubcircuitInfo(). However, if a comparison reveals an Export name
* mismatch then you must call purgeCompareList() after which it
* doesn't matter what you do for the rest of the compareList. */
public void beginNextCompareList(String subcktName) {
this.subcktName = subcktName;
compareListID++;
purgeCurrentCompareList = false;
cellsInCompareList.clear();
cellsInSharedCellGroups = null;
}
/** Restrict subcircuit detection. We only want to detect a subcircuit if
* its corresponding CellGroup is instantiated by both Cells begin compared.
* When we perform a hierarchical comparison we need to rescan the
* sub-hierarchies for each pair of Cells being compared.
* <p>
* Also, we should not detect a subcircuit if the Cell is in the current
* compare list. Here's the weird case that motivates this. Suppose B{lay}
* instantiates A{lay}. Suppose the designer compares A{sch} with B{lay}.
* NCC builds a compare list with A{sch}, A{lay}, and B{lay}. NCC might
* first compare A{sch} with A{lay}. Then when NCC compares A{sch} with
* B{lay} it will fail because A gets treated as a subcircuit. However,
* if NCC first compares A{sch} with B{lay} then the second comparison:
* A{sch} with A{lay} will pass. Unfortunately, NCC's choice is random.
* Successive runs produce different results.
* <p>
* In general the compare list might have n schematics and m layouts and
* the schematics may instantiate one-another and the layouts might
* instantiate one another. If we prevent all the schematics and layouts
* from being treated as subcells then any order of comparison should
* pass. */
public void restrictSubcktDetection(CellContext cc1, CellContext cc2,
Set compareListCells) {
List<CompareList> compareLists = CompareLists.getCompareLists(cc1, cc2);
cellsInSharedCellGroups = new HashSet<Cell>();
for (CompareList compareList : compareLists) {
for (Iterator<CellContext> it2=compareList.iterator(); it2.hasNext();) {
Cell c = it2.next().cell;
if (!compareListCells.contains(c)) cellsInSharedCellGroups.add(c);
}
}
}
/** Add new subcircuit information for each Cell in the compareList so it
* can be treated as a subcircuit primitive in a future
* hierarchical comparison at a higher level. This method must be called
* for each Cell in the compareList.
* <p>However, if a comparison reveals an Export name mismatch then you must
* call purgeCurrentCompareList() after which it doesn't matter what
* you do. */
public void addSubcircuitInfo(Cell c, SubcircuitInfo subcktInfo) {
if (purgeCurrentCompareList) return;
Job.error(cellToSubcktInfo.containsKey(c),
"SubcircuitInfo already exists for Cell");
cellsInCompareList.add(c);
cellToSubcktInfo.put(c, subcktInfo);
}
/** You must call this method if a Cell comparison reveals an Export name
* mismatch. In that case we can no longer treat cells in compareList as a
* subcircuit primitives at higher levels. Instead we must purge all
* information related to Cells in this compareList so that we will flatten
* through them when comparing from higher levels in the hierarchy. */
public void purgeCurrentCompareList() {
purgeCurrentCompareList = true;
for (Cell c : cellsInCompareList) {
Job.error(!cellToSubcktInfo.containsKey(c), "Cell not in map?");
cellToSubcktInfo.remove(c);
}
cellsInCompareList.clear();
}
/** name of the subcircuit being compared */
public String currentSubcircuitName() {return subcktName;}
/** unique int ID of subcircuit being compared */
public int currentSubcircuitID() {return compareListID;}
/** should I treat an instance of this cell as a subcircuit primitive
* in the current comparison? */
public boolean treatAsPrimitive(Cell c) {
return cellToSubcktInfo.containsKey(c) &&
(cellsInSharedCellGroups==null ||
cellsInSharedCellGroups.contains(c));
}
/** get me information I need to treat an instance of this Cell as a
* subcircuit primitive */
public SubcircuitInfo getSubcircuitInfo(Cell c) {
return (SubcircuitInfo) cellToSubcktInfo.get(c);
}
}