/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: LocalPartitioning.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. */ /** * This is the second generation algorithm for local partitioning of Wires. * It's intended to be more efficient. (That is not O(n^2) in number of * Port instances.) */ package com.sun.electric.tool.ncc.processing; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.electric.database.text.TextUtils; import com.sun.electric.tool.ncc.NccGlobals; import com.sun.electric.tool.ncc.lists.LeafList; import com.sun.electric.tool.ncc.netlist.NetObject; import com.sun.electric.tool.ncc.netlist.Part; import com.sun.electric.tool.ncc.netlist.PinType; import com.sun.electric.tool.ncc.netlist.Wire; import com.sun.electric.tool.ncc.strategy.Strategy; import com.sun.electric.tool.ncc.trees.EquivRecord; import com.sun.electric.tool.Job; /** * Partition Wires into equivalence classes based only upon * local information. Compute a Signature for each wire and then * group together Wires with the same Signature. */ public class LocalPartitionWires { // ------------------------ data --------------------------------- private final NccGlobals globals; // ------------------------ classes --------------------------------- private static class PinTypeCount { private PinType pinType; private int count; @Override public boolean equals(Object o) { if (!(o instanceof PinTypeCount)) return false; PinTypeCount p = (PinTypeCount) o; return p.count==count && p.pinType==pinType; } @Override public int hashCode() { return pinType.hashCode() * count; } public PinTypeCount(PinType t) {pinType=t;} public void increment() {count++;} public String description() { return count+" "+pinType.description(); } } // Sort PinTypeCounts by PinType name private static class PinTypeCompare implements Comparator<PinTypeCount> { public int compare(PinTypeCount c1, PinTypeCount c2) { String n1 = c1.pinType.description(); String n2 = c2.pinType.description(); return TextUtils.STRING_NUMBER_ORDER.compare(n1, n2); } } /** A Wire's Signature is an unordered list of of the pairs {PinType, count}. * For example, 2 Mos diffusions and 1 Mos gate. Signatures are used as * hash keys to quickly partition Wires based upon their Signatures. */ public static class Signature { private Map<PinType,PinTypeCount> pinTypeToPinTypeCount = new HashMap<PinType,PinTypeCount>(); // Note: id isn't supposed to be used by equals() private Integer id; private List<PinTypeCount> getListOfPinTypeCounts() { List<PinTypeCount> l = new ArrayList<PinTypeCount>(); for (PinType t : pinTypeToPinTypeCount.keySet()) { PinTypeCount c = pinTypeToPinTypeCount.get(t); l.add(c); } return l; } @Override public int hashCode() { int code = 0; for (PinType t : pinTypeToPinTypeCount.keySet()) { PinTypeCount c = pinTypeToPinTypeCount.get(t); code += t.hashCode() + c.hashCode(); } return code; } @Override public boolean equals(Object o) { if (!(o instanceof Signature)) return false; Signature s2 = (Signature) o; if (pinTypeToPinTypeCount.size()!=s2.pinTypeToPinTypeCount.size()) return false; for (PinType t : pinTypeToPinTypeCount.keySet()) { PinTypeCount c = pinTypeToPinTypeCount.get(t); PinTypeCount c2 = s2.pinTypeToPinTypeCount.get(t); if (!c.equals(c2)) return false; } return true; } public void increment(PinType t) { PinTypeCount c = pinTypeToPinTypeCount.get(t); if (c==null) { c = new PinTypeCount(t); pinTypeToPinTypeCount.put(t, c); } c.increment(); } public void setID(int id) { Job.error(this.id!=null, "assigned a second ID?"); this.id = new Integer(id); } public Integer getID() {return id;} public List<String> getReasons() { List<PinTypeCount> pinTypeCounts = getListOfPinTypeCounts(); Collections.sort(pinTypeCounts, new PinTypeCompare()); List<String> pinTypeDescrs = new ArrayList<String>(); if (pinTypeCounts.size()==0) { pinTypeDescrs.add("disconnected"); } else { for (PinTypeCount t : pinTypeCounts) { String descr = t.description(); pinTypeDescrs.add(descr); } } return pinTypeDescrs; } } private static class ComputeSignatures extends Strategy { private Map<Wire,Signature> wireToSignature = new HashMap<Wire,Signature>(); private Signature disconnectedWireSignature = new Signature(); // Set signatures for Wires with nothing attached private void doFor(Wire w) { if (w.numParts()==0) { wireToSignature.put(w, disconnectedWireSignature); } } // Compute signatures for all Wires attached to PortInsts private void doFor(Part p) { int pinNdx=0; for (Iterator<Wire> itw=p.getConnected(); itw.hasNext(); pinNdx++) { Wire w = itw.next(); PinType t = p.getPinTypeOfNthPin(pinNdx); Signature s = wireToSignature.get(w); if (s==null) { s = new Signature(); wireToSignature.put(w, s); } s.increment(t); } } @Override public Integer doFor(NetObject no) { if (no instanceof Part) { doFor((Part)no); } else if (no instanceof Wire) { doFor((Wire)no); } return Strategy.CODE_NO_CHANGE; } private ComputeSignatures(NccGlobals globs) {super(globs);} private Map<Wire,Signature> doYourJob2() { EquivRecord root = globals.getRoot(); // don't blow up if no Parts Wires or Ports if (root!=null) doFor(root); return wireToSignature; } // Calculate a signature for each Wire public static Map<Wire,Signature> doYourJob(NccGlobals globs) { return (new ComputeSignatures(globs)).doYourJob2(); } } // If two Signatures are != but are .equals() then discard one of them. // Assign each remaining Signature a unique Integer ID. private void cannonizeSignatures(Map<Wire,Signature> wireToSignature) { Map<Signature,Signature> signatures = new HashMap<Signature,Signature>(); int sigID = 0; for (Wire w : wireToSignature.keySet()) { Signature s = wireToSignature.get(w); Signature cannonicalS = signatures.get(s); if (cannonicalS==null) { cannonicalS = s; signatures.put(cannonicalS, cannonicalS); cannonicalS.setID(sigID++); } else { wireToSignature.put(w, cannonicalS); } } } private static class StratLocalPartitionWires extends Strategy { private Map<Wire,Signature> wireToSignature; private Set<Wire> forcedMatchWires; private StratLocalPartitionWires(Map<Wire,Signature> wireToSignature, Set<Wire> forcedMatchWires, NccGlobals globals) { super(globals); this.wireToSignature = wireToSignature; this.forcedMatchWires = forcedMatchWires; } @Override public Integer doFor(NetObject o) { Wire w = (Wire) o; if (forcedMatchWires.contains(w)) { // don't repartition Wires that were forced to match return 0; } else { Signature s = wireToSignature.get(w); // add 1000 to avoid collision with 0 which means "don't partition" return 1000 + s.getID(); } } private void summary(LeafList offspring) { globals.status2("StratLocalPartitionWires produced " + offspring.size() + " offspring"); if (offspring.size()!=0) { globals.status2(offspring.sizeInfoString()); globals.status2(offspringStats(offspring)); } } private void doYourJob2(EquivRecord wireRec) { LeafList offspring = doFor(wireRec); summary(offspring); } public static void doYourJob(Map<Wire,Signature> wireToSignature, Set<Wire> forcedMatchWires, NccGlobals globs) { (new StratLocalPartitionWires(wireToSignature, forcedMatchWires, globs)) .doYourJob2(globs.getWires()); } } // Add a signature to each Wire partition private static class SignPartitions extends Strategy { private Map<Wire,Signature> wireToSignature; // Pass signature from doFor(NetObject) to doFor(EquivRecord) private Signature lastSignature; @Override public LeafList doFor(EquivRecord er) { LeafList l = super.doFor(er); if (er.isLeaf()) er.setWireSignature(lastSignature); return l; } @Override public Integer doFor(NetObject no) { lastSignature = wireToSignature.get(no); return Strategy.CODE_NO_CHANGE; } private SignPartitions(Map<Wire,Signature> wireToSignature, NccGlobals globs) { super(globs); this.wireToSignature = wireToSignature; } public static void doYourJob(Map<Wire,Signature> wireToSignature, NccGlobals globs) { (new SignPartitions(wireToSignature, globs)) .doFor(globs.getWires()); } } private LocalPartitionWires(NccGlobals globs) {globals=globs;} private void doYourJob(Set<Wire> forcedMatchWires) { EquivRecord wires = globals.getWires(); if (wires==null) return; // don't blow up if no Wires Map<Wire,Signature> wireToSignature = ComputeSignatures.doYourJob(globals); cannonizeSignatures(wireToSignature); StratLocalPartitionWires.doYourJob(wireToSignature, forcedMatchWires, globals); SignPartitions.doYourJob(wireToSignature, globals); } // ------------------------ public method --------------------------------- /** Partition Wires based upon purely local information * @param forcedMatchWires Wires that were pre-matched by the user * @param globs variables used by all of NCC */ public static void doYourJob(Set<Wire> forcedMatchWires, NccGlobals globs) { globs.status2("Partition Wires using local information"); LocalPartitionWires lpw = new LocalPartitionWires(globs); lpw.doYourJob(forcedMatchWires); } }