/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: PadGenerator.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.generator; import com.sun.electric.database.EditingPreferences; import com.sun.electric.database.geometry.DBMath; import com.sun.electric.database.geometry.Dimension2D; import com.sun.electric.database.geometry.EGraphics; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.Orientation; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.geometry.PolyBase; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.CellName; import com.sun.electric.database.text.Name; import com.sun.electric.database.text.TextUtils; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.database.variable.TextDescriptor; import com.sun.electric.database.variable.UserInterface; import com.sun.electric.lib.LibFile; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.technologies.Artwork; import com.sun.electric.technology.technologies.Generic; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import com.sun.electric.tool.io.FileType; import com.sun.electric.tool.io.input.LibraryFiles; import com.sun.electric.tool.routing.AutoStitch; import com.sun.electric.tool.routing.AutoStitch.AutoOptions; import com.sun.electric.tool.user.CellChangeJobs; import com.sun.electric.tool.user.User; import com.sun.electric.tool.user.ViewChanges; import com.sun.electric.tool.user.IconParameters; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; /** * Class to generate pad frames from a specification file. */ public class PadGenerator { /** * Method to generate a pad frame from an array file. * Schedules a change job to generate the pad frame. * @param destLib destination library. * @param fileName the array file name. */ public static void makePadFrame(Library destLib, String fileName) { if (fileName == null) return; EditingPreferences ep = destLib.getEditingPreferences(); new MakePadFrame(destLib, fileName, ep.getAlignmentToGrid()); } /** * Method to generate a pad frame from an array file. * Presumes that it is being run from inside a change job. * @param destLib destination library. * @param fileName the array file name. * @param job the Job running this task (null if none). */ public static Cell makePadFrameUseJob(Library destLib, String fileName, Dimension2D alignment, Job job) { PadGenerator pg = new PadGenerator(destLib, fileName, alignment); return pg.makePadFrame(job); } private static class MakePadFrame extends Job { private Library destLib; private String fileName; private Cell frameCell; private Dimension2D alignment; private MakePadFrame(Library destLib, String fileName, Dimension2D alignment) { super("Pad Frame Generator", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.destLib = destLib; this.fileName = fileName; this.alignment = alignment; startJob(); } public boolean doIt() throws JobException { frameCell = makePadFrameUseJob(destLib, fileName, alignment, this); fieldVariableChanged("frameCell"); return true; } public void terminateOK() { UserInterface ui = Job.getUserInterface(); ui.displayCell(frameCell); } } private Library destLib; // destination library private String fileName; // name of file with pad array instructions private Dimension2D alignment; // alignment amount private String padframename; // name of pad frame cell private String corename; // core cell to stick in pad frame private int lineno; // line no of the pad array file we are processing private Library cellLib; // library containing pad cells private boolean copycells; // if we copy cells into the library with the pad ring private List<View> views; // list of strings defining views of pad frame to create. private int angle; // angle of placed instances private HashMap<String,ArrayAlign> alignments; // how to align adjacent instances private HashMap<String,PadExports> exports; // which ports to export private List<Object> orderedCommands; // list of orderedCommands to do private boolean coreAllOnOneSide = false; private IconParameters iconParameters = IconParameters.makeInstance(true); private static class ArrayAlign { int lineno; String cellname; String inport; String outport; } private static class PadExports { int lineno; String cellname; String padname; String corename; } private static class PlacePad { int lineno; String cellname; String exportsname; int gap; NodeInst ni; List<PortAssociate> associations; List<ExportAssociate> exportAssociations; Double locx; Double locy; } private static class Rotation { int angle; } private static class ReverseDirection { } private static class PortAssociate { boolean export; String portname; String assocname; } private static class ExportAssociate { String padportName; String exportName; } private PadGenerator(Library destLib, String fileName, Dimension2D alignment) { this.destLib = destLib; this.fileName = fileName; this.alignment = alignment; alignments = new HashMap<String,ArrayAlign>(); exports = new HashMap<String,PadExports>(); views = new ArrayList<View>(); angle = 0; lineno = 1; orderedCommands = new ArrayList<Object>(); } private Cell makePadFrame(Job job) { String lineRead; File inputFile = new File(fileName); if (inputFile == null || !inputFile.canRead()) { System.out.println("Error reading file "+fileName); return null; } try { FileReader readFile = new FileReader(inputFile); BufferedReader readLine = new BufferedReader(readFile); lineRead = readLine.readLine(); while (lineRead != null) { StringTokenizer str = new StringTokenizer(lineRead, " \t"); if (str.hasMoreTokens()) { String keyWord = str.nextToken(); if (keyWord.charAt(0) != ';') { do { if (keyWord.equals("celllibrary")) { if (!processCellLibrary(str)) return null; continue; } else if (keyWord.equals("views")) { if (!processViews(str)) return null; continue; } else if (keyWord.equals("cell")) { if (!processCell(str)) return null; continue; } else if (keyWord.equals("core")) { if (!processCore(str)) return null; continue; } else if (keyWord.equals("rotate")) { if (!processRotate(str)) return null; continue; } else if (keyWord.equals("reverse")) { if (!processReverse(str)) return null; continue; } else if (keyWord.equals("align")) { if (!processAlign(str)) return null; continue; } else if (keyWord.equals("export")) { if (!processExport(str)) return null; continue; } else if (keyWord.equals("place")) { if (!processPlace(str)) return null; continue; } else if (keyWord.equals("coreExportsAllOnOneSideOfIcon")) { coreAllOnOneSide = true; continue; } System.out.println("Line " + lineno + ": unknown keyword'" + keyWord + "'"); break; } while (str.hasMoreTokens()); } } lineRead = readLine.readLine(); lineno++; } } catch (IOException e1) {} Cell frameCell = createPadFrames(job); return frameCell; } /** * Process the celllibrary keyword * @return true on success, false on error. */ private boolean processCellLibrary(StringTokenizer str) { String keyWord; if (str.hasMoreTokens()) { keyWord = str.nextToken(); URL fileURL = TextUtils.makeURLToFile(keyWord); cellLib = Library.findLibrary(TextUtils.getFileNameWithoutExtension(fileURL)); if (cellLib == null) { // library does not exist: see if in same directory is pad frame file StringBuffer errmsg = new StringBuffer(); String fileDir = TextUtils.getFilePath(TextUtils.makeURLToFile(fileName)); fileURL = TextUtils.makeURLToFile(fileDir + keyWord); if (!TextUtils.URLExists(fileURL, errmsg)) { // library does not exist: see if file can be found locally if (!TextUtils.URLExists(fileURL, errmsg)) { // try the Electric library area fileURL = LibFile.getLibFile(keyWord); if (!TextUtils.URLExists(fileURL, errmsg)) { System.out.println(errmsg.toString()); return false; } } } FileType style = FileType.DEFAULTLIB; if (TextUtils.getExtension(fileURL).equals("txt")) style = FileType.READABLEDUMP; if (TextUtils.getExtension(fileURL).equals("elib")) style = FileType.ELIB; cellLib = LibraryFiles.readLibrary(fileURL, null, style, false, iconParameters); if (cellLib == null) { err("cannot read library " + keyWord); return false; } } } if (str.hasMoreTokens()) { keyWord = str.nextToken(); if (keyWord.equals("copy")) copycells = true; } return true; } /** * Process any Views. * @return true on success, false on error. */ private boolean processViews(StringTokenizer str) { String keyWord; while (str.hasMoreTokens()) { keyWord = str.nextToken(); View view = View.findView(keyWord); if (view != null) views.add(view); else err("Unknown view '" + keyWord + "', ignoring"); } return true; } /** * Process the cell keyword * @return true on success, false on error. */ private boolean processCell(StringTokenizer str) { if (str.hasMoreTokens()) { padframename = str.nextToken(); return true; } return false; } /** * Process the core keyword * @return true on success, false on error. */ private boolean processCore(StringTokenizer str) { if (str.hasMoreTokens()) { corename = str.nextToken(); return true; } return false; } /** * Process the rotate keyword * @return true on success, false on error. */ private boolean processRotate(StringTokenizer str) { String keyWord; int angle = 0; if (str.hasMoreTokens()) { keyWord = str.nextToken(); if (keyWord.equals("c")) { angle = 2700; } else if (keyWord.equals("cc")) { angle = 900; } else { System.out.println("Line " + lineno + ": incorrect rotation " + keyWord); return false; } Rotation rot = new Rotation(); rot.angle = angle; orderedCommands.add(rot); return true; } return false; } private boolean processReverse(StringTokenizer str) { orderedCommands.add(new ReverseDirection()); return true; } /** * Process the align keyword * @return true on success, false on error. */ private boolean processAlign(StringTokenizer str) { String keyWord; ArrayAlign aa = new ArrayAlign(); aa.lineno = lineno; keyWord = str.nextToken(); if (keyWord.equals("")) { System.out.println("Line " + lineno + ": missing 'cell' name"); return false; } aa.cellname = keyWord; keyWord = str.nextToken(); if (keyWord.equals("")) { System.out.println("Line " + lineno + ": missing 'in port' name"); return false; } aa.inport = keyWord; keyWord = str.nextToken(); if (keyWord.equals("")) { System.out.println("Line " + lineno + ": missing 'out port' name"); return false; } aa.outport = keyWord; alignments.put(aa.cellname, aa); return true; } /** * Process the export keyword * @return true on success, false on error. */ private boolean processExport(StringTokenizer str) { String keyWord; PadExports pe = new PadExports(); pe.lineno = lineno; pe.padname = null; pe.corename = null; keyWord = str.nextToken(); if (keyWord.equals("")) { System.out.println("Line " + lineno + ": missing 'cell' name"); return false; } pe.cellname = keyWord; if (str.hasMoreTokens()) { keyWord = str.nextToken(); pe.padname = keyWord; if (str.hasMoreTokens()) { keyWord = str.nextToken(); pe.corename = keyWord; } } exports.put(pe.cellname, pe); return true; } private boolean processPlace(StringTokenizer str) { PlacePad pad = new PlacePad(); pad.lineno = lineno; pad.exportsname = null; pad.gap = 0; pad.ni = null; pad.associations = new ArrayList<PortAssociate>(); pad.exportAssociations = new ArrayList<ExportAssociate>(); pad.locx = null; pad.locy = null; if (!str.hasMoreTokens()) { err("Cell name missing"); return false; } pad.cellname = str.nextToken(); while (str.hasMoreTokens()) { String keyWord = str.nextToken(); if (keyWord.equals("export")) { // export xxx=xxxx if (!str.hasMoreTokens()) { err("Missing export assignment after 'export' keyword"); return false; } keyWord = str.nextToken(); ExportAssociate ea = new ExportAssociate(); ea.padportName = getLHS(keyWord); if (ea.padportName == null) { err("Bad export assignment after 'export' keyword"); return false; } ea.exportName = getRHS(keyWord, str); if (ea.exportName == null) { err("Bad export assignment after 'export' keyword"); return false; } pad.exportAssociations.add(ea); } else { // name=xxxx or gap=xxxx String lhs = getLHS(keyWord); String rhs = getRHS(keyWord, str); if (lhs == null || rhs == null) { err("Parse error on assignment of " + keyWord); return false; } if (lhs.equals("gap")) { try { pad.gap = Integer.parseInt(rhs); } catch (java.lang.NumberFormatException e) { err("Error parsing integer for 'gap' = " + rhs); return false; } } else if (lhs.equals("name")) { pad.exportsname = rhs; } else if (lhs.equals("x")) { try { pad.locx = new Double(rhs); } catch (NumberFormatException e) { System.out.println(e.getMessage()); pad.locx = null; } } else if (lhs.equals("y")) { try { pad.locy = new Double(rhs); } catch (NumberFormatException e) { System.out.println(e.getMessage()); pad.locy = null; } } else { // port association PortAssociate pa = new PortAssociate(); pa.export = false; pa.portname = lhs; pa.assocname = rhs; pad.associations.add(pa); } } } orderedCommands.add(pad); return true; } private String getLHS(String keyword) { if (keyword.indexOf("=") != -1) { return keyword.substring(0, keyword.indexOf("=")); } return keyword; } private String getRHS(String keyword, StringTokenizer str) { if (keyword.indexOf("=") != -1) { if (keyword.substring(keyword.indexOf("=") + 1).equals("")) { // LHS= RHS if (!str.hasMoreTokens()) return null; return str.nextToken(); } // LHS=RHS return keyword.substring(keyword.indexOf("=") + 1); } if (!str.hasMoreTokens()) return null; keyword = str.nextToken(); if (keyword.equals("=")) { // LHS = RHS if (!str.hasMoreTokens()) return null; return str.nextToken(); } // LHS =RHS return keyword.substring(keyword.indexOf("=") + 1); } /** * Print the error message with the current line number. * @param msg */ private void err(String msg) { System.out.println("Line " + lineno + ": " + msg); } private Cell createPadFrames(Job job) { Cell frameCell = null; if (views.size() == 0) { frameCell = createPadFrame(padframename, View.LAYOUT, job); } else { for (View view : views) { if (view == View.SCHEMATIC) view = View.ICON; frameCell = createPadFrame(padframename, view, job); } } return frameCell; } private Cell createPadFrame(String name, View view, Job job) { angle = 0; // first, try to create cell CellName n = CellName.parseName(name); if (n != null && (n.getView() == null || n.getView() == View.UNKNOWN)) { // no view in cell name, append appropriately if (view == null) { name = name + "{lay}"; } else { if (view == View.ICON) { // create a schematic, place icons of pads in it name = name + "{sch}"; } else { name = name + "{" + view.getAbbreviation() + "}"; } } } Cell framecell = Cell.makeInstance(destLib, name); if (framecell == null) { System.out.println("Could not create pad frame Cell: " + name); return null; } EditingPreferences ep = framecell.getEditingPreferences(); List<Export> padPorts = new ArrayList<Export>(); List<Export> corePorts = new ArrayList<Export>(); NodeInst lastni = null; int lastRotate = 0; String lastpadname = null; boolean reversed = false; // cycle through all orderedCommands, doing them for (Object obj : orderedCommands) { // Rotation commands are ordered with respect to Place commands. if (obj instanceof Rotation) { angle = (angle + ((Rotation) obj).angle) % 3600; continue; } if (obj instanceof ReverseDirection) { reversed = !reversed; continue; } // otherwise this is a Place command PlacePad pad = (PlacePad) obj; lineno = pad.lineno; // get cell String cellname = pad.cellname; if (!cellname.endsWith("}")) { if (view != null) cellname = cellname + "{" + view.getAbbreviation() + "}"; } Cell cell = cellLib.findNodeProto(cellname); if (cell == null) { err("Could not create pad Cell: " + cellname); continue; } // if copying cell, copy it into current library if (copycells) { Cell existing = cell; cell = null; for(Iterator<Cell> cIt = destLib.getCells(); cIt.hasNext(); ) { Cell thereCell = cIt.next(); if (thereCell.getName().equals(existing.getName()) && thereCell.getView() == existing.getView()) { cell = thereCell; break; } } if (cell == null) { List<Cell> fromCells = new ArrayList<Cell>(); fromCells.add(existing); CellChangeJobs.copyRecursively(fromCells, destLib, false, false, false, true, true, null); for(Iterator<Cell> cIt = destLib.getCells(); cIt.hasNext(); ) { Cell thereCell = cIt.next(); if (thereCell.getName().equals(existing.getName()) && thereCell.getView() == existing.getView()) { cell = thereCell; break; } } if (cell == null) { err("Could not copy in pad Cell " + cellname); continue; } } } // get array alignment for this cell ArrayAlign aa = alignments.get(pad.cellname); if (aa == null) { err("No port alignment for cell " + pad.cellname); continue; } int gapx = 0, gapy = 0; double centerX = 0, centerY = 0; if (lastni != null) { // get info on last nodeinst created ArrayAlign lastaa = alignments.get(lastpadname); // get previous node's outport - use it to place this nodeinst PortProto pp = (lastni.getProto()).findPortProto(lastaa.outport); if (pp == null) { err("no port called '" + lastaa.outport + "' on " + lastni); continue; } Poly poly = (lastni.findPortInstFromProto(pp)).getPoly(); centerX = poly.getCenterX(); centerY = poly.getCenterY(); } Point2D pointCenter = new Point2D.Double(centerX, centerY); boolean flipLR = false; boolean flipUD = false; if (reversed) flipUD = true; Orientation orient = Orientation.fromJava(angle, flipLR, flipUD); NodeInst ni = NodeInst.makeInstance(cell, pointCenter, cell.getDefWidth(), cell.getDefHeight(), framecell, orient, null); if (ni == null) { err("problem creating" + cell + " instance"); continue; } if (lastni != null) { int gap = pad.gap; if (reversed) gap = -gap; switch (lastRotate) { case 0: gapx = gap; gapy = 0; break; case 900: gapx = 0; gapy = gap; break; case 1800: gapx = -gap; gapy = 0; break; case 2700: gapx = 0; gapy = -gap; break; } PortProto inport = cell.findPortProto(aa.inport); if (inport == null) { err("No port called '" + aa.inport + "' on " + cell); continue; } Poly poly = ni.findPortInstFromProto(inport).getPoly(); double tempx = centerX - poly.getCenterX() + gapx; double tempy = centerY - poly.getCenterY() + gapy; ni.move(tempx, tempy); } double dx = 0, dy = 0; if (pad.locx != null) dx = pad.locx.doubleValue() - ni.getAnchorCenterX(); if (pad.locy != null) dy = pad.locy.doubleValue() - ni.getAnchorCenterY(); ni.move(dx, dy); // create exports // get export for this cell, if any if (pad.exportsname != null) { PadExports pe = exports.get(pad.cellname); if (pe != null) { // pad export Export pppad = cell.findExport(pe.padname); if (pppad == null) { err("no port called '" + pe.padname + "' on Cell " + cell.noLibDescribe()); } else { pppad = Export.newInstance(framecell, ni.findPortInstFromProto(pppad), pad.exportsname); if (pppad == null) err("Creating export " + pad.exportsname); else { TextDescriptor td = pppad.getTextDescriptor(Export.EXPORT_NAME); pppad.setTextDescriptor(Export.EXPORT_NAME, td.withAbsSize(14)); padPorts.add(pppad); } } // core export if (pe.corename != null) { Export ppcore = cell.findExport(pe.corename); if (ppcore == null) { err("no port called '" + pe.corename + "' on Cell " + cell.noLibDescribe()); } else { ppcore = Export.newInstance(framecell, ni.findPortInstFromProto(ppcore), "core_" + pad.exportsname); if (ppcore == null) err("Creating export core_" + pad.exportsname); else { TextDescriptor td = ppcore.getTextDescriptor(Export.EXPORT_NAME).withAbsSize(14); corePorts.add(ppcore); ppcore.setTextDescriptor(Export.EXPORT_NAME, td); } } } else { corePorts.add(null); } } } // create exports from export pad=name command for (ExportAssociate ea : pad.exportAssociations) { Export pp = cell.findExport(ea.padportName); if (pp == null) { err("no port called '" + ea.padportName + "' on Cell " + cell.noLibDescribe()); } else { pp = Export.newInstance(framecell, ni.findPortInstFromProto(pp), ea.exportName); if (pp == null) err("Creating export "+ea.exportName); else { TextDescriptor td = pp.getTextDescriptor(Export.EXPORT_NAME).withAbsSize(14); corePorts.add(pp); pp.setTextDescriptor(Export.EXPORT_NAME, td); } } } lastni = ni; lastRotate = angle; lastpadname = pad.cellname; pad.ni = ni; } // auto stitch everything AutoOptions prefs = new AutoOptions(); prefs.createExports = false; AutoStitch.runAutoStitch(framecell, null, null, job, null, null, true, false, prefs, false, null); if (corename != null) { // first, try to create cell String corenameview = corename; CellName coreName = CellName.parseName(corename); if (view != null && coreName.getView() == View.UNKNOWN) { corenameview = corename + "{" + view.getAbbreviation() + "}"; } Cell corenp = destLib.findNodeProto(corenameview); if (corenp == null) { System.out.println("Line " + lineno + ": cannot find core cell " + corenameview); } else { Rectangle2D bounds = framecell.getBounds(); Point2D center = new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()); DBMath.gridAlign(center, alignment); NodeInst ni = NodeInst.makeInstance(corenp, center, corenp.getDefWidth(), corenp.getDefHeight(), framecell); Map<Export,PortInst> trueBusEnd = new HashMap<Export,PortInst>(); for (Object obj : orderedCommands) { if (obj instanceof PlacePad) { PlacePad pad = (PlacePad) obj; for (PortAssociate pa : pad.associations) { if (pad.ni == null) continue; boolean nameArc = false; PortInst pi1 = null; PortProto corepp = corenp.findPortProto(pa.assocname); if (corepp != null) pi1 = ni.findPortInstFromProto(corepp); if (pi1 == null) { // see if there are bus ports on the core for(Iterator<PortProto> it = corenp.getPorts(); it.hasNext(); ) { Export e = (Export)it.next(); Name eName = e.getNameKey(); int wid = eName.busWidth(); if (wid <= 1) continue; for(int i=0; i<wid; i++) { if (eName.subname(i).toString().equals(pa.assocname)) { pi1 = trueBusEnd.get(e); if (pi1 == null) { // make a short bus arc from the port to a bus pin which gets used for connections PortInst pi = ni.findPortInstFromProto(e); PolyBase portPoly = pi.getPoly(); Rectangle2D portRect = portPoly.getBounds2D(); PrimitiveNode busPinProto = Schematics.tech().busPinNode; NodeInst busPin = NodeInst.makeInstance(busPinProto, new EPoint(portRect.getCenterX(), portRect.getCenterY()), busPinProto.getDefWidth(), busPinProto.getDefHeight(), framecell); pi1 = busPin.getOnlyPortInst(); ArcProto busArcProto = Schematics.tech().bus_arc; ArcInst.makeInstance(busArcProto, pi, pi1); trueBusEnd.put(e, pi1); } nameArc = true; break; } } if (pi1 != null) break; } } if (pi1 == null) { PortInst pi = pad.ni.findPortInst(pa.portname); Export.newInstance(pad.ni.getParent(), pi, pa.assocname); continue; } PortInst pi2 = pad.ni.findPortInst(pa.portname); if (pi2 == null) { err("no port called '" + pa.portname + "' on Cell " + pad.cellname); continue; } ArcProto ap = Generic.tech().unrouted_arc; ArcInst ai = ArcInst.newInstanceBase(ap, ap.getDefaultLambdaBaseWidth(), pi1, pi2); if (nameArc) { ai.setName(pa.assocname); } else { // give generated name based on the connection String netName = "PADFRAME"; if (pad.exportAssociations != null && pad.exportAssociations.size() > 0) netName += "_" + pad.exportAssociations.get(0).exportName; netName += "_" + pa.assocname; ai.setName(netName); } } } } } } if (view == View.ICON) { // This is a crock until the functionality here can be folded // into CircuitChanges.makeIconViewCommand() // get icon style controls double leadLength = ep.iconGenLeadLength; double leadSpacing = ep.iconGenLeadSpacing; // create the new icon cell String iconCellName = framecell.getName() + "{ic}"; Cell iconCell = Cell.makeInstance(destLib, iconCellName); if (iconCell == null) { Job.getUserInterface().showErrorMessage("Cannot create Icon cell " + iconCellName, "Icon creation failed"); return framecell; } iconCell.setWantExpanded(); // determine the size of the "black box" core double ySize = Math.max(Math.max(padPorts.size(), corePorts.size()), 5) * leadSpacing; double xSize = 3 * leadSpacing; // create the "black box" NodeInst bbNi = null; if (ep.iconGenDrawBody) { bbNi = NodeInst.newInstance(Artwork.tech().openedThickerPolygonNode, new Point2D.Double(0, 0), xSize, ySize, iconCell); if (bbNi == null) return framecell; bbNi.newVar(Artwork.ART_COLOR, new Integer(EGraphics.RED)); EPoint[] points = new EPoint[5]; points[0] = new EPoint(-0.5 * xSize, -0.5 * ySize); points[1] = new EPoint(-0.5 * xSize, 0.5 * ySize); points[2] = new EPoint(0.5 * xSize, 0.5 * ySize); points[3] = new EPoint(0.5 * xSize, -0.5 * ySize); points[4] = new EPoint(-0.5 * xSize, -0.5 * ySize); bbNi.setTrace(points); // put the original cell name on it bbNi.newDisplayVar(Schematics.SCHEM_FUNCTION, framecell.getName()); } // get icon preferences int exportTech = ep.iconGenExportTech; boolean drawLeads = ep.iconGenDrawLeads; int exportStyle = ep.iconGenExportStyle; int exportLocation = ep.iconGenExportLocation; boolean ad = ep.iconsAlwaysDrawn; if (coreAllOnOneSide) { List<Export> padTemp = new ArrayList<Export>(); List<Export> coreTemp = new ArrayList<Export>(); for (Export pp : padPorts) { if (pp.getName().startsWith("core_")) coreTemp.add(pp); else padTemp.add(pp); } for (Export pp : corePorts) { if (pp == null) { coreTemp.add(pp); continue; } if (pp.getName().startsWith("core_")) coreTemp.add(pp); else padTemp.add(pp); } padPorts = padTemp; corePorts = coreTemp; } // place pins around the Black Box int total = 0; int leftSide = padPorts.size(); int rightSide = corePorts.size(); for (Export pp : padPorts) { if (pp.isBodyOnly()) continue; // determine location of the port double spacing = leadSpacing; double xPos = 0, yPos = 0; double xBBPos = 0, yBBPos = 0; xBBPos = -xSize / 2; xPos = xBBPos - leadLength; if (leftSide * 2 < rightSide) spacing = leadSpacing * 2; yBBPos = yPos = ySize / 2 - ((ySize - (leftSide - 1) * spacing) / 2 + total * spacing); int rotation = ViewChanges.iconTextRotation(pp); if (IconParameters.makeIconExport(pp, 0, xPos, yPos, xBBPos, yBBPos, iconCell, rotation)) total++; } total = 0; for (Export pp : corePorts) { if (pp == null) { total++; continue; } if (pp.isBodyOnly()) continue; // determine location of the port double spacing = leadSpacing; double xPos = 0, yPos = 0; double xBBPos = 0, yBBPos = 0; xBBPos = xSize / 2; xPos = xBBPos + leadLength; if (rightSide * 2 < leftSide) spacing = leadSpacing * 2; yBBPos = yPos = ySize / 2 - ((ySize - (rightSide - 1) * spacing) / 2 + total * spacing); int rotation = ViewChanges.iconTextRotation(pp); if (IconParameters.makeIconExport(pp, 1, xPos, yPos, xBBPos, yBBPos, iconCell, rotation)) total++; } // if no body, leads, or cell center is drawn, and there is only 1 export, add more if (!ep.iconGenDrawBody && !ep.iconGenDrawLeads && ep.placeCellCenter && total <= 1) { NodeInst.newInstance(Generic.tech().invisiblePinNode, new Point2D.Double(0, 0), xSize, ySize, iconCell); } // place an icon in the schematic int exampleLocation = ep.iconGenInstanceLocation; Point2D iconPos = new Point2D.Double(0, 0); Rectangle2D cellBounds = framecell.getBounds(); Rectangle2D iconBounds = iconCell.getBounds(); double halfWidth = iconBounds.getWidth() / 2; double halfHeight = iconBounds.getHeight() / 2; switch (exampleLocation) { case 0: // upper-right iconPos.setLocation(cellBounds.getMaxX() + halfWidth, cellBounds.getMaxY() + halfHeight); break; case 1: // upper-left iconPos.setLocation(cellBounds.getMinX() - halfWidth, cellBounds.getMaxY() + halfHeight); break; case 2: // lower-right iconPos.setLocation(cellBounds.getMaxX() + halfWidth, cellBounds.getMinY() - halfHeight); break; case 3: // lower-left iconPos.setLocation(cellBounds.getMinX() - halfWidth, cellBounds.getMinY() - halfHeight); break; } DBMath.gridAlign(iconPos, alignment); double px = iconCell.getBounds().getWidth(); double py = iconCell.getBounds().getHeight(); NodeInst.makeInstance(iconCell, iconPos, px, py, framecell); } return framecell; } }