package com.sun.electric.tool.generator.flag; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.hierarchy.Cell.CellGroup; import com.sun.electric.database.hierarchy.HierarchyEnumerator.CellInfo; import com.sun.electric.database.hierarchy.HierarchyEnumerator.Visitor; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.network.Network; import com.sun.electric.database.text.Name; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.database.variable.Variable; import com.sun.electric.tool.generator.flag.router.ToConnect; import com.sun.electric.tool.generator.layout.LayoutLib; import com.sun.electric.tool.Job; public class SchematicVisitor extends Visitor { private static final Variable.Key LAYOUT_SPACE_KEY = Variable.newKey("ATTR_LAYOUT_SPACE"); private final Cell layCell; private SchematicPosition schPos = new SchematicPosition(); private List<NodeInst> layInsts = new ArrayList<NodeInst>(); private Map<NodeInst, SchematicPosition> layInstToSchPos = new HashMap<NodeInst, SchematicPosition>(); private Map<NodeInst, Double> layInstToSpacing = new HashMap<NodeInst, Double>(); private Map<Integer, ToConnect> netIdToToConn = new HashMap<Integer, ToConnect>(); private static final void prln(String msg) {Utils.prln(msg);} private Cell findLayout(Cell icon) { CellGroup group = icon.getCellGroup(); for (Iterator<Cell> cIt=group.getCells(); cIt.hasNext();) { Cell c = cIt.next(); if (c.getView()==View.LAYOUT) return c; } return null; } private void getLayConnectionsFromIcon(Cell icon, Nodable iconInst, NodeInst layInst, CellInfo info) { Netlist nl = info.getNetlist(); for (Iterator eIt=icon.getExports(); eIt.hasNext();) { Export e = (Export) eIt.next(); Name eNmKey = e.getNameKey(); int busWid = eNmKey.busWidth(); for (int i=0; i<busWid; i++) { String subNm = eNmKey.subname(i).toString(); PortInst layPortInst = layInst.findPortInst(subNm); if (layPortInst==null) { prln("layout Cell: "+layInst.getProto().getName()+ " missing port: "+subNm); continue; } Network net = nl.getNetwork(iconInst, e, i); int netID = info.getNetID(net); ToConnect conn = netIdToToConn.get(netID); if (conn==null) { conn = new ToConnect(); netIdToToConn.put(netID, conn); } conn.addPortInst(layPortInst); } } } // The name "foo[3]__bar is illegal in Electric because the // array reference is inside the name. Change inner array // refs to use _ instead: "foo_3___bar". private String removeInnerArrayRefs(String instNm) { final int LEN = instNm.length(); char[] chars = new char[LEN]; boolean findMatchOpen = false; for (int i=LEN-1; i>=0; i--) { chars[i] = instNm.charAt(i); if (i==LEN-1 && chars[i]==']') { findMatchOpen = true; continue; } if (findMatchOpen && chars[i]=='[') { findMatchOpen = false; continue; } if (chars[i]==']' || chars[i]=='[') { chars[i] = '_'; } } if (findMatchOpen) { // Never found a matching open. Delete the close chars[LEN-1] = '_'; } return new String(chars); } private double getLayoutSpacing(Nodable no) { NodeInst iconInst = no.getNodeInst(); Variable v = iconInst.getVar(LAYOUT_SPACE_KEY); if (v==null) return 0; Object o = v.getObject(); if (o instanceof Integer) return ((Integer)o).doubleValue(); if (o instanceof Float) return ((Float)o).doubleValue(); if (o instanceof Double) return ((Double)o).doubleValue(); return 0; } private boolean useCellLayout(Cell iconSch) { FlagAnnotations ann = new FlagAnnotations(iconSch); return ann.isAtomic() || ann.isAutoGen(); } public boolean visitNodeInst(Nodable no, CellInfo info) { // ignore primitives if (!no.isCellInstance()) return false; Cell schematic = no.getParent(); Cell icon = (Cell) no.getProto(); // for schematic X discard icons X Cell iconSch = icon.getEquivalent(); if (iconSch==schematic) return false; // expand Cells that are not layout primitives if (!useCellLayout(iconSch)) return true; // Icon is a layout primitive, get layout Cell lay = findLayout(icon); Job.error(lay==null, "Can't find layout for icon: "+icon.getName()); NodeInst layInst = LayoutLib.newNodeInst(lay, 0, 0, 0, 0, 0, layCell); String instNm = info.getUniqueNodableName(no, "__"); layInst.setName(removeInnerArrayRefs(instNm)); layInsts.add(layInst); SchematicPosition copy = schPos.copy(); copy.push(no.getNodeInst().getBounds().getMinX()); layInstToSchPos.put(layInst, copy); layInstToSpacing.put(layInst, getLayoutSpacing(no)); getLayConnectionsFromIcon(icon, no, layInst, info); return false; } public boolean enterCell(CellInfo info) { if (info.isRootCell()) { // create ToConnect for every exported Network Netlist nl = info.getNetlist(); for (Iterator<Network> netIt=nl.getNetworks(); netIt.hasNext();) { Network net = netIt.next(); Iterator<String> expIt = net.getExportedNames(); if (expIt.hasNext()) { List<String> expNms = new ArrayList<String>(); while (expIt.hasNext()) expNms.add(expIt.next()); netIdToToConn.put(info.getNetID(net), new ToConnect(expNms)); } } } else { Nodable parentInst = info.getParentInst(); schPos.push(parentInst.getNodeInst().getBounds().getMinX()); } return true; } public void exitCell(CellInfo info) { if (!info.isRootCell()) schPos.pop(); } public SchematicVisitor(Cell layCell) { this.layCell = layCell; } public List<ToConnect> getLayoutToConnects() { List<ToConnect> toConnects = new ArrayList<ToConnect>(); for (Integer i : netIdToToConn.keySet()) toConnects.add(netIdToToConn.get(i)); return toConnects; } public List<NodeInst> getLayInsts() { return layInsts; } public Map<NodeInst, SchematicPosition> getLayInstSchematicPositions() { return layInstToSchPos; } /** when stacking layout instances, user may request extra space between * a particular instance and its predecessor */ public Map<NodeInst, Double> getLayInstSpacing() { return layInstToSpacing; } }