/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: GetNetlist.java
* Silicon compiler tool (QUISC): read a netlist
* Written by Andrew R. Kostiuk, Queen's University.
* Translated to Java by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2005, 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.sc;
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.NodeProto;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.util.TextUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This is the netlist reader of the Silicon Compiler tool.
*/
public class GetNetlist
{
/***********************************************************************
General Constants
------------------------------------------------------------------------*/
private static final int GND = 0;
private static final int PWR = 1;
/***** Directions that ports can be attached to *****/
/** mask for port direction */ public static final int PORTDIRMASK = 0x0000000F;
/** port direction up */ public static final int PORTDIRUP = 0x00000001;
/** port direction down */ public static final int PORTDIRDOWN = 0x00000002;
/** port direction right */ public static final int PORTDIRRIGHT= 0x00000004;
/** port direction left */ public static final int PORTDIRLEFT = 0x00000008;
/** port type mask */ public static final int PORTTYPE = 0x000003F0;
/** ground port */ public static final int GNDPORT = 0x00000010;
/** power port */ public static final int PWRPORT = 0x00000020;
/** bidirectional port */ public static final int BIDIRPORT = 0x00000040;
/** output port */ public static final int OUTPORT = 0x00000080;
/** input port */ public static final int INPORT = 0x00000100;
/** unknown port */ public static final int UNPORT = 0x00000200;
/***********************************************************************
QUISC Cell Structure
------------------------------------------------------------------------*/
static class SCCell
{
/** name of complex cell */ String name;
/** maximum number of nodes */ int maxNodeNum;
/** list of instances for cell */ List<SCNiTree> niList;
/** extracted nodes */ ExtNode exNodes;
/** flags for processing cell */ int bits;
/** list of power ports */ ExtNode power;
/** list of ground ports */ ExtNode ground;
/** list of ports */ SCPort ports, lastPort;
/** placement information of cell */ Place.SCPlace placement;
/** routing information for cell */ Route.SCRoute route;
/** next in list of SC cells */ SCCell next;
};
static class SCPort
{
/** name of port */ String name;
/** special node */ SCNiTree node;
/** cell on which this port resides */ SCCell parent;
/** port attributes */ int bits;
/** pointer to next port */ SCPort next;
};
static class SCCellNums
{
/** active area from top */ int topActive;
/** active are from bottom */ int bottomActive;
/** active area from left */ int leftActive;
/** active are from right */ int rightActive;
};
/***********************************************************************
Instance Tree Structure
------------------------------------------------------------------------*/
/***** Types of Instances *****/
public static final int LEAFCELL = 0;
public static final int COMPLEXCELL = 1;
public static final int SPECIALCELL = 2;
public static final int FEEDCELL = 3;
public static final int STITCH = 4;
public static final int LATERALFEED = 5;
static class SCNiTree
{
/** name of instance */ String name;
/** alternative number of node */ int number;
/** type of instance */ int type;
/** leaf cell or SCCell if complex */ Object np;
/** x size if leaf cell */ double size;
/** pointer to connection list */ ConList connect;
/** list of io ports and ext nodes */ SCNiPort ports;
/** list of actual power ports */ SCNiPort power;
/** list of actual ground ports */ SCNiPort ground;
/** bits for silicon compiler */ int flags;
/** generic temporary pointer */ Object tp;
/**
* Method to create a new instance with a given name and type.
* @param name name of the instance.
* @param type type of the instance.
*/
SCNiTree(String name, int type)
{
this.name = name;
this.type = type;
this.number = 0;
this.np = null;
this.size = 0;
this.connect = null;
this.ports = null;
this.power = null;
this.ground = null;
this.flags = 0;
this.tp = null;
}
};
static class SCNiPort
{
/** leaf port or SCPort if on cell */ Object port;
/** extracted node */ ExtNode extNode;
/** bits for processing */ int bits;
/** x position if leaf port */ double xPos;
/** list of instance ports */ SCNiPort next;
SCNiPort() {}
SCNiPort(SCNiTree instance)
{
this.port = null;
this.extNode = null;
this.bits = 0;
this.xPos = 0;
this.next = instance.ports;
instance.ports = this;
}
};
/***********************************************************************
Connection Structures
------------------------------------------------------------------------*/
private static class ConList
{
/** pointer to port on node A */ SCNiPort portA;
/** pointer to node B */ SCNiTree nodeB;
/** pointer to port on node B */ SCNiPort portB;
/** pointer to extracted node */ ExtNode extNode;
/** pointer to next list element */ ConList next;
};
/***********************************************************************
Extraction Structures
------------------------------------------------------------------------*/
private static class ExtPort
{
/** instance of extracted node */ SCNiTree node;
/** instance port */ SCNiPort port;
/** next in list of common node */ ExtPort next;
};
/**
* Class for communicating netlist information to the placer and router.
*/
public static class ExtNode
{
/** optional name of port */ String name;
/** link list of ports */ ExtPort firstPort;
/** flags for processing */ int flags;
/** generic pointer for processing */ Object ptr;
/** link list of nodes */ ExtNode next;
};
SCCell scCells, curSCCell;
/**
* Read the netlist associated with the current cell.
* @return true on error.
*/
public boolean readNetCurCell(Cell cell)
{
scCells = null;
curSCCell = null;
if (cell.getView() != View.NETLISTQUISC)
{
System.out.println("Current cell must have QUISC Netlist view");
return true;
}
String [] strings = cell.getTextViewContents();
if (strings == null)
{
System.out.println("Cell " + cell.describe(true) + " has no text in it");
return true;
}
// read entire netlist
boolean errors = false;
for(int i=0; i<strings.length; i++)
{
String inBuf = strings[i].trim();
// check for a comment line or empty line
if (inBuf.length() == 0 || inBuf.charAt(0) == '!') continue;
// break into keywords
List<String> parameters = new ArrayList<String>();
for(int sPtr = 0; sPtr < inBuf.length(); sPtr++)
{
// get rid of leading white space
while (sPtr < inBuf.length() && (inBuf.charAt(sPtr) == ' ' || inBuf.charAt(sPtr) == '\t')) sPtr++;
if (sPtr >= inBuf.length()) break;
// check for string
if (inBuf.charAt(sPtr) == '"')
{
sPtr++;
int endQuote = inBuf.indexOf('"', sPtr);
if (endQuote < 0)
{
System.out.println("ERROR line " + (i+1) + ": Unbalanced quotes ");
errors = true;
break;
}
parameters.add(inBuf.substring(sPtr, endQuote));
sPtr = endQuote;
} else
{
int endSpace = inBuf.indexOf(' ', sPtr);
int endTab = inBuf.indexOf('\t', sPtr);
if (endSpace < 0) endSpace = endTab;
if (endSpace < 0) endSpace = inBuf.length();
if (endTab >= 0 && endTab < endSpace) endSpace = endTab;
parameters.add(inBuf.substring(sPtr, endSpace));
sPtr = endSpace;
}
}
String err = parse(parameters);
if (err != null)
{
System.out.println("ERROR line " + (i+1) + ": " + err);
System.out.println(" Line: " + inBuf);
errors = true;
break;
}
}
// do the "pull" (extract)
String err = pull();
if (err != null)
{
System.out.println(err);
errors = true;
}
return errors;
}
/**
* Main parsing routine for the Silicon Compiler.
*/
private String parse(List<String> keywords)
{
if (keywords.size() == 0) return null;
String mainKeyword = keywords.get(0);
if (mainKeyword.equalsIgnoreCase("connect")) return connect(keywords);
if (mainKeyword.equalsIgnoreCase("create")) return create(keywords);
if (mainKeyword.equalsIgnoreCase("export")) return export(keywords);
if (mainKeyword.equalsIgnoreCase("extract")) return extract(keywords);
if (mainKeyword.equalsIgnoreCase("set")) return xSet(keywords);
return "Unknown keyword: " + mainKeyword;
}
/**************************************** NETLIST READING: THE CREATE KEYWORD ****************************************/
private String create(List<String> keywords)
{
if (keywords.size() <= 1) return "No keyword for CREATE command";
String sPtr = keywords.get(1);
if (sPtr.equalsIgnoreCase("cell"))
{
if (keywords.size() <= 2) return "No name for CREATE CELL command";
sPtr = keywords.get(2);
// check if cell already exists in cell list
for(SCCell cell = scCells; cell != null; cell = cell.next)
{
if (sPtr.equalsIgnoreCase(cell.name))
return "Cell '" + sPtr + "' already exists in current library";
}
// generate warning message if a leaf cell of the same name exists
if (findLeafCell(sPtr) != null)
System.out.println("WARNING - cell " + sPtr + " may be overridden by created cell");
// create new cell
SCCell newCell = new SCCell();
newCell.name = sPtr;
newCell.maxNodeNum = 0;
newCell.niList = new ArrayList<SCNiTree>();
newCell.exNodes = null;
newCell.bits = 0;
newCell.power = null;
newCell.ground = null;
newCell.ports = null;
newCell.lastPort = null;
newCell.placement = null;
newCell.route = null;
newCell.next = scCells;
scCells = newCell;
curSCCell = newCell;
// create dummy ground and power nodes
SCNiTree ntp = findNi(curSCCell, "ground");
if (ntp != null) return "Instance 'ground' already exists";
ntp = new SCNiTree("ground", SPECIALCELL);
curSCCell.niList.add(ntp);
new SCNiPort(ntp);
ntp.number = curSCCell.maxNodeNum++;
ntp = findNi(curSCCell, "power");
if (ntp != null) return "Instance 'power' already exists";
ntp = new SCNiTree("power", SPECIALCELL);
curSCCell.niList.add(ntp);
new SCNiPort(ntp);
ntp.number = curSCCell.maxNodeNum++;
return null;
}
if (sPtr.equalsIgnoreCase("instance"))
{
if (keywords.size() <= 2) return "No instance name for CREATE INSTANCE command";
String noden = keywords.get(2);
if (keywords.size() <= 3) return "No type name for CREATE INSTANCE command";
String nodep = keywords.get(3);
// search for cell in cell list
SCCell cell = null;
for(SCCell c = scCells; c != null; c = c.next)
{
if (nodep.equalsIgnoreCase(c.name)) { cell = c; break; }
}
Object proto = cell;
int type = COMPLEXCELL;
double size = 0;
if (cell == null)
{
// search for leaf cell in library
Cell bc = findLeafCell(nodep);
if (bc == null)
return "There is no '" + nodep + "' in the standard cell library";
proto = bc;
type = LEAFCELL;
size = SilComp.leafCellXSize(bc);
}
// check if currently working in a cell
if (curSCCell == null) return "No cell selected";
// check if instance name already exits
SCNiTree ntp = findNi(curSCCell, noden);
if (ntp != null)
return "Instance '" + noden + "' already exists";
// add instance name to tree
ntp = new SCNiTree(noden, type);
curSCCell.niList.add(ntp);
ntp.number = curSCCell.maxNodeNum++;
ntp.np = proto;
ntp.size = size;
// create ni port list
if (type == COMPLEXCELL)
{
SCNiPort oldNiPort = null;
for (SCPort port = ((SCCell)proto).ports; port != null; port = port.next)
{
SCNiPort niPort = new SCNiPort();
niPort.port = port;
niPort.extNode = null;
niPort.bits = 0;
niPort.xPos = 0;
switch (port.bits & PORTTYPE)
{
case GNDPORT:
niPort.next = ntp.ground;
ntp.ground = niPort;
break;
case PWRPORT:
niPort.next = ntp.power;
ntp.power = niPort;
break;
default:
niPort.next = null;
if (oldNiPort == null)
{
ntp.ports = niPort;
} else
{
oldNiPort.next = niPort;
}
oldNiPort = niPort;
break;
}
}
} else
{
SCNiPort oldNiPort = null;
Cell realCell = (Cell)proto;
for(Iterator<PortProto> it = realCell.getPorts(); it.hasNext(); )
{
Export bp = (Export)it.next();
SCNiPort niPort = new SCNiPort();
niPort.port = bp;
niPort.extNode = null;
niPort.bits = 0;
niPort.xPos = SilComp.leafPortXPos(bp);
switch (getLeafPortType(bp))
{
case GNDPORT:
niPort.next = ntp.ground;
ntp.ground = niPort;
break;
case PWRPORT:
niPort.next = ntp.power;
ntp.power = niPort;
break;
default:
niPort.next = null;
if (oldNiPort == null)
{
ntp.ports = niPort;
} else
{
oldNiPort.next = niPort;
}
oldNiPort = niPort;
break;
}
}
}
return null;
}
return "Unknown CREATE command: " + sPtr;
}
/**
* Method to find the location in a SCNiTree where the node should be placed.
* If the pointer does not have a value of null, then the object already exits.
*/
private SCNiTree findNi(SCCell cell, String name)
{
for(SCNiTree nPtr : cell.niList)
{
if (nPtr.name.equalsIgnoreCase(name)) return nPtr;
}
return null;
}
/**************************************** NETLIST READING: THE CONNECT KEYWORD ****************************************/
private String connect(List<String> keywords)
{
if (keywords.size() < 4) return "Not enough parameters for CONNECT command";
// search for the first node
String node0Name = keywords.get(1);
String port0Name = keywords.get(2);
SCNiTree ntpA = findNi(curSCCell, node0Name);
if (ntpA == null) return "Cannot find instance '" + node0Name + "'";
SCNiPort portA = findPp(ntpA, port0Name);
if (portA == null)
return "Cannot find port '" + port0Name + "' on instance '" + node0Name + "'";
// search for the second node
String node1Name = keywords.get(3);
SCNiTree ntpB = findNi(curSCCell, node1Name);
if (ntpB == null) return "Cannot find instance '" + node1Name + "'";
// check for special power or ground node
SCNiPort portB = ntpB.ports;
if (ntpB.type != SPECIALCELL)
{
if (keywords.size() < 5) return "Not enough parameters for CONNECT command";
String port1Name = keywords.get(4);
portB = findPp(ntpB, port1Name);
if (portB == null)
return "Cannot find port '" + port1Name + "' on instance '" + node1Name + "'";
}
conList(ntpA, portA, ntpB, portB);
return null;
}
/**
* Method to find the port on the given node instance.
* @return null if port is not found.
*/
private SCNiPort findPp(SCNiTree ntp, String name)
{
SCNiPort port = null;
if (ntp == null) return null;
switch (ntp.type)
{
case SPECIALCELL:
return ntp.ports;
case COMPLEXCELL:
for (port = ntp.ports; port != null; port = port.next)
{
if (((SCPort)port.port).name.equalsIgnoreCase(name)) break;
}
break;
case LEAFCELL:
for (port = ntp.ports; port != null; port = port.next)
{
Export pp = (Export)port.port;
if (pp.getName().equalsIgnoreCase(name)) break;
}
break;
}
return port;
}
/**
* Method to add a connection count for the two node instances indicated.
*/
private void conList(SCNiTree ntpA, SCNiPort portA, SCNiTree ntpB, SCNiPort portB)
{
// add connection to instance A
ConList cl = new ConList();
cl.portA = portA;
cl.nodeB = ntpB;
cl.portB = portB;
cl.extNode = null;
// add to head of the list
cl.next = ntpA.connect;
ntpA.connect = cl;
// add connection to instance B
cl = new ConList();
cl.portA = portB;
cl.nodeB = ntpA;
cl.portB = portA;
cl.extNode = null;
// add to head of the list
cl.next = ntpB.connect;
ntpB.connect = cl;
}
/**************************************** NETLIST READING: THE EXPORT KEYWORD ****************************************/
private String export(List<String> keywords)
{
// check to see if working in a cell
if (curSCCell == null) return "No cell selected";
// search current cell for node
if (keywords.size() <= 1) return "No instance specified for EXPORT command";
String instName = keywords.get(1);
SCNiTree nPtr = findNi(curSCCell, instName);
if (nPtr == null) return "Cannot find instance '" + instName + "' for EXPORT command";
// search for port
if (keywords.size() <= 2) return "No port specified for EXPORT command";
String portName = keywords.get(2);
SCNiPort port = findPp(nPtr, portName);
if (port == null)
return "Cannot find port '" + portName + "' on instance '" + instName + "' for EXPORT command";
// check for export name
if (keywords.size() <= 3) return "No export name specified for EXPORT command";
String exportName = keywords.get(3);
// check possible port type
int type = UNPORT;
if (keywords.size() >= 5)
{
String typeName = keywords.get(4);
if (typeName.equalsIgnoreCase("input"))
{
type = INPORT;
} else if (typeName.equalsIgnoreCase("output"))
{
type = OUTPORT;
} else if (typeName.equalsIgnoreCase("bidirectional"))
{
type = BIDIRPORT;
} else
{
return "Unknown port type '" + typeName + "' for EXPORT command";
}
}
// create special node
SCNiTree searchNPtr = findNi(curSCCell, exportName);
if (searchNPtr != null) return "Export name '" + exportName + "' is not unique";
SCNiTree newNPtr = new SCNiTree(exportName, SPECIALCELL);
curSCCell.niList.add(newNPtr);
newNPtr.number = curSCCell.maxNodeNum++;
searchNPtr = newNPtr;
SCNiPort niPort = new SCNiPort();
niPort.port = null;
niPort.extNode = null;
niPort.next = null;
newNPtr.ports = niPort;
// add to export port list
SCPort newPort = new SCPort();
niPort.port = newPort;
newPort.name = exportName;
newPort.node = newNPtr;
newPort.parent = curSCCell;
newPort.bits = type;
newPort.next = null;
if (curSCCell.lastPort == null)
{
curSCCell.ports = curSCCell.lastPort = newPort;
} else
{
curSCCell.lastPort.next = newPort;
curSCCell.lastPort = newPort;
}
// add to connect list
conList(nPtr, port, newNPtr, niPort);
return null;
}
/**************************************** NETLIST READING: THE SET KEYWORD ****************************************/
/**
* Method to handle the "SET" keyword.
* Current options are:
* 1. leaf-cell-numbers = Magic numbers for leaf cells.
* 2. node-name = Name an extracted node.
* 3. port-direction = Direction allowed to attach to a port.
*/
private String xSet(List<String> keywords)
{
if (keywords.size() <= 1) return "No option for SET command";
String whatToSet = keywords.get(1);
if (whatToSet.equalsIgnoreCase("leaf-cell-numbers"))
{
String cellName = keywords.get(2);
Cell leafCell = findLeafCell(cellName);
if (leafCell == null) return "Cannot find cell '" + cellName + "'";
SCCellNums cNums = getLeafCellNums(leafCell);
int numPar = 3;
while (numPar < keywords.size())
{
String parName = keywords.get(numPar);
if (parName.equalsIgnoreCase("top-active"))
{
numPar++;
if (numPar < keywords.size())
cNums.topActive = TextUtils.atoi(keywords.get(numPar++));
continue;
}
if (parName.equalsIgnoreCase("bottom-active"))
{
numPar++;
if (numPar < keywords.size())
cNums.bottomActive = TextUtils.atoi(keywords.get(numPar++));
continue;
}
if (parName.equalsIgnoreCase("left-active"))
{
numPar++;
if (numPar < keywords.size())
cNums.leftActive = TextUtils.atoi(keywords.get(numPar++));
continue;
}
if (parName.equalsIgnoreCase("right-active"))
{
numPar++;
if (numPar < keywords.size())
cNums.rightActive = TextUtils.atoi(keywords.get(numPar++));
continue;
}
return "Unknown option '" + parName + "' for SET LEAF-CELL-NUMBERS command";
}
setLeafCellNums(leafCell, cNums);
return null;
}
if (whatToSet.equalsIgnoreCase("node-name"))
{
// check for sufficient parameters
if (keywords.size() <= 4) return "Insufficent parameters for SET NODE-NAME command";
// search for instance
String instName = keywords.get(2);
SCNiTree instPtr = findNi(curSCCell, instName);
if (instPtr == null)
return "Cannot find instance '" + instName + "' in SET NODE-NAME command";
// search for port on instance
String portName = keywords.get(3);
SCNiPort iPort;
for (iPort = instPtr.ports; iPort != null; iPort = iPort.next)
{
if (instPtr.type == LEAFCELL)
{
Export e = (Export)iPort.port;
if (e.getName().equalsIgnoreCase(portName)) break;
} else if (instPtr.type == COMPLEXCELL)
{
SCPort scp = (SCPort)iPort.port;
if (scp.name.equalsIgnoreCase(portName)) break;
}
}
if (iPort == null)
return "Cannot find port '" + portName + "' on instance '" + instName + "' in SET NODE-NAME command";
// set extracted node name if possible
if (iPort.extNode == null) return "Cannot find extracted node to set name in SET NODE-NAME command";
iPort.extNode.name = keywords.get(4);
return null;
}
if (whatToSet.equalsIgnoreCase("port-direction"))
{
String cellName = keywords.get(2);
String portName = keywords.get(3);
SCCell cell;
for (cell = scCells; cell != null; cell = cell.next)
{
if (cell.name.equalsIgnoreCase(cellName)) break;
}
int bits = 0;
if (cell == null)
{
Cell leafCell = findLeafCell(cellName);
if (leafCell == null)
return "Cannot find cell '" + cellName + "'";
Export leafPort = leafCell.findExport(portName);
if (leafPort == null) return "Cannot find port '" + portName + "' on cell '" + cellName + "'";
} else
{
SCPort port;
for (port = cell.ports; port != null; port = port.next)
{
if (port.name.equalsIgnoreCase(portName)) break;
}
if (port == null)
return "Cannot find port '" + portName + "' on cell '" + cellName + "'";
bits = port.bits;
}
bits &= ~PORTDIRMASK;
String dir = keywords.get(4);
for(int i=0; i<dir.length(); i++)
{
char dirCh = dir.charAt(i);
switch (dirCh)
{
case 'u': bits |= PORTDIRUP; break;
case 'd': bits |= PORTDIRDOWN; break;
case 'r': bits |= PORTDIRRIGHT; break;
case 'l': bits |= PORTDIRLEFT; break;
default:
return "Unknown port direction specifier '" + dir + "'";
}
}
return null;
}
return "Unknown option '" + whatToSet+ "' for SET command";
}
/**
* Method to fill in the cell_nums structure for the indicated leaf cell.
*/
static SCCellNums getLeafCellNums(Cell leafCell)
{
SCCellNums sNums = new SCCellNums();
// // check if variable exits
// var = getvalkey((INTBIG)leafCell, VNODEPROTO, VINTEGER|VISARRAY, sc_numskey);
// if (var != NOVARIABLE)
// {
// iarray = (int *)nums;
// i = sizeof(SCCellNums) / sizeof(int);
// iarray = (int *)nums;
// jarray = (int *)var->addr;
// for (j = 0; j < i; j++) iarray[j] = jarray[j];
// }
return sNums;
}
/**
* Method to set the cell_nums variable for the indicated leaf cell.
*/
static void setLeafCellNums(Cell leafCell, SCCellNums nums)
{
// VARIABLE *var;
// int i, j, *iarray;
// INTBIG *jarray;
//
// i = sizeof(SCCellNums) / sizeof(int);
//
// // check if variable exits
// var = getvalkey((INTBIG)leafCell, VNODEPROTO, VINTEGER|VISARRAY, sc_numskey);
// if (var == NOVARIABLE)
// {
// if ((jarray = emalloc((i + 1) * sizeof(INTBIG), sc_tool->cluster)) == 0)
// return(Sc_seterrmsg(SC_NOMEMORY));
// iarray = (int *)nums;
// for (j = 0; j < i; j++) jarray[j] = iarray[j];
// jarray[j] = -1;
// if (setvalkey((INTBIG)leafCell, VNODEPROTO, sc_numskey, (INTBIG)jarray,
// VINTEGER | VISARRAY) == NOVARIABLE)
// return(Sc_seterrmsg(SC_NOSET_CELL_NUMS));
// return(SC_NOERROR);
// }
// iarray = (int *)nums;
// jarray = (INTBIG *)var->addr;
// for (j = 0; j < i; j++) jarray[j] = iarray[j];
// return(SC_NOERROR);
}
/**
* Method to find the named cell.
* Looks in the main cell library, too.
*/
private Cell findLeafCell(String name)
{
NodeProto np = Cell.findNodeProto(name);
if (!(np instanceof Cell)) np = null;
Cell cell = (Cell)np;
Library lib = Library.findLibrary(SilComp.SCLIBNAME);
if (cell == null && lib != null)
{
cell = lib.findNodeProto(name);
if (cell == null) return null;
}
if (cell != null)
{
Cell layCell = cell.otherView(View.LAYOUT);
if (layCell != null) cell = layCell;
}
return cell;
}
/**************************************** NETLIST READING: THE EXTRACT KEYWORD ****************************************/
/**
* Method to extract the node netlist for a given cell.
*/
private String extract(List keywords)
{
if (curSCCell == null) return "No cell selected";
extractClearFlag(curSCCell);
curSCCell.exNodes = null;
extractFindNodes(curSCCell);
// get ground nodes
curSCCell.ground = new ExtNode();
curSCCell.ground.name = "ground";
curSCCell.ground.flags = 0;
curSCCell.ground.ptr = null;
curSCCell.ground.firstPort = null;
curSCCell.ground.next = null;
ExtNode oldNList = curSCCell.exNodes;
for (ExtNode nList = curSCCell.exNodes; nList != null; nList = nList.next)
{
ExtPort oldPList = nList.firstPort;
ExtPort pList;
for (pList = nList.firstPort; pList != null; pList = pList.next)
{
if (pList.node.number == GND)
{
curSCCell.ground.firstPort = nList.firstPort;
if (oldNList == nList)
{
curSCCell.exNodes = nList.next;
} else
{
oldNList.next = nList.next;
}
if (oldPList == pList)
{
curSCCell.ground.firstPort = pList.next;
} else
{
oldPList.next = pList.next;
}
break;
}
oldPList = pList;
}
if (pList != null) break;
oldNList = nList;
}
for (ExtPort pList = curSCCell.ground.firstPort; pList != null; pList = pList.next)
pList.port.extNode = curSCCell.ground;
// get power nodes
curSCCell.power = new ExtNode();
curSCCell.power.name = "power";
curSCCell.power.flags = 0;
curSCCell.power.ptr = null;
curSCCell.power.firstPort = null;
curSCCell.power.next = null;
oldNList = curSCCell.exNodes;
for (ExtNode nList = curSCCell.exNodes; nList != null; nList = nList.next)
{
ExtPort oldPList = nList.firstPort;
ExtPort pList;
for (pList = nList.firstPort; pList != null; pList = pList.next)
{
if (pList.node.number == PWR)
{
curSCCell.power.firstPort = nList.firstPort;
if (oldNList == nList)
{
curSCCell.exNodes = nList.next;
} else
{
oldNList.next = nList.next;
}
if (oldPList == pList)
{
curSCCell.power.firstPort = pList.next;
} else
{
oldPList.next = pList.next;
}
break;
}
oldPList = pList;
}
if (pList != null) break;
oldNList = nList;
}
for (ExtPort pList = curSCCell.power.firstPort; pList != null; pList = pList.next)
pList.port.extNode = curSCCell.power;
extractFindPower(curSCCell, curSCCell);
extractCollectUnconnected(curSCCell);
// give the names of the cell ports to the extracted node
for (SCPort port = curSCCell.ports; port != null; port = port.next)
{
switch (port.bits & PORTTYPE)
{
case PWRPORT:
case GNDPORT:
break;
default:
// Note that special nodes only have one niport
port.node.ports.extNode.name = port.name;
break;
}
}
// give arbitrary names to unnamed extracted nodes
int nodenum = 2;
for (ExtNode ext = curSCCell.exNodes; ext != null; ext = ext.next)
{
if (ext.name == null) ext.name = "n" + (nodenum++);
}
return null;
}
/**
* Method to clear the extract pointer on all node instance ports.
*/
private void extractClearFlag(SCCell cell)
{
for (SCNiTree ntp : cell.niList)
{
ntp.flags &= Place.BITS_EXTRACT;
for (SCNiPort port = ntp.ports; port != null; port = port.next)
port.extNode = null;
}
}
/**
* Method to go though the INSTANCE list, finding all resultant connections.
*/
private void extractFindNodes(SCCell cell)
{
for (SCNiTree niTree : cell.niList)
{
niTree.flags |= Place.BITS_EXTRACT;
for (ConList cl = niTree.connect; cl != null; cl = cl.next)
{
extractSnake(niTree, cl.portA, cl);
}
}
}
/**
* Method to snake through connection list extracting common connections.
*/
private void extractSnake(SCNiTree nodeA, SCNiPort portA, ConList cl)
{
for ( ; cl != null; cl = cl.next)
{
if (cl.portA != portA) continue;
if (portA != null && portA.extNode != null)
{
if (!(cl.portB != null && cl.portB.extNode != null))
{
extractAddNode(portA.extNode, cl.nodeB, cl.portB);
if ((cl.nodeB.flags & Place.BITS_EXTRACT) == 0)
{
cl.nodeB.flags |= Place.BITS_EXTRACT;
extractSnake(cl.nodeB, cl.portB, cl.nodeB.connect);
cl.nodeB.flags ^= Place.BITS_EXTRACT;
}
}
} else
{
if (cl.portB != null && cl.portB.extNode != null)
{
extractAddNode(cl.portB.extNode, nodeA, portA);
} else
{
ExtNode common = extractAddNode(null, nodeA, portA);
common = extractAddNode(common, cl.nodeB, cl.portB);
if ((cl.nodeB.flags & Place.BITS_EXTRACT) == 0)
{
cl.nodeB.flags |= Place.BITS_EXTRACT;
extractSnake(cl.nodeB, cl.portB, cl.nodeB.connect);
cl.nodeB.flags ^= Place.BITS_EXTRACT;
}
}
}
}
}
/**
* Method to add a node and port to a ExtNode list.
* Modify the root if necessary.
*/
private ExtNode extractAddNode(ExtNode simNode, SCNiTree node, SCNiPort port)
{
ExtPort newPort = new ExtPort();
if (simNode == null)
{
simNode = new ExtNode();
simNode.firstPort = newPort;
simNode.flags = 0;
simNode.ptr = null;
simNode.name = null;
newPort.node = node;
newPort.port = port;
if (port != null)
port.extNode = simNode;
newPort.next = null;
simNode.next = curSCCell.exNodes;
curSCCell.exNodes = simNode;
} else
{
newPort.node = node;
newPort.port = port;
if (port != null)
port.extNode = simNode;
newPort.next = simNode.firstPort;
simNode.firstPort = newPort;
}
return simNode;
}
/**
* Method to find the implicit power and ground ports.
* Does a search of the instance tree and adds to the appropriate port list.
* Skips over the dummy ground and power instances and special cells.
*/
private void extractFindPower(SCCell cell, SCCell vars)
{
for (SCNiTree ntp : cell.niList)
{
// process node
if (ntp.number > PWR)
{
switch (ntp.type)
{
case COMPLEXCELL:
break;
case SPECIALCELL:
break;
case LEAFCELL:
for (SCNiPort port = ntp.ground; port != null; port = port.next)
{
ExtPort pList = new ExtPort();
pList.node = ntp;
pList.port = port;
port.extNode = vars.ground;
pList.next = vars.ground.firstPort;
vars.ground.firstPort = pList;
}
for (SCNiPort port = ntp.power; port != null; port = port.next)
{
ExtPort pList = new ExtPort();
pList.node = ntp;
pList.port = port;
port.extNode = vars.power;
pList.next = vars.power.firstPort;
vars.power.firstPort = pList;
}
break;
default:
break;
}
}
}
}
/**************************************** PLACEMENT ****************************************/
/**
* Method to flatten all complex cells in the current cell.
* It does this by creating instances of all instances from the
* complex cells in the current cell. To insure the uniqueness of all
* instance names, the new instances have names "parent_inst.inst"
* where "parent_inst" is the name of the instance being expanded and
* "inst" is the name of the subinstance being pulled up.
*/
private String pull()
{
// check if a cell is currently selected
if (curSCCell == null) return "No cell selected";
// remember the original ones and delete them later
List<SCNiTree> cellList = new ArrayList<SCNiTree>();
for (SCNiTree inst : curSCCell.niList)
{
if (inst.type == COMPLEXCELL)
cellList.add(inst);
}
// expand all instances of complex cell type
for (SCNiTree inst : cellList)
{
String err = pullInst(inst, curSCCell);
if (err != null) return err;
}
// now remove the original ones
List<SCNiTree> deleteList = new ArrayList<SCNiTree>();
for (SCNiTree inst : curSCCell.niList)
{
if (inst.type == COMPLEXCELL)
deleteList.add(inst);
}
for (SCNiTree inst : deleteList)
{
curSCCell.niList.remove(inst);
}
return null;
}
/**
* Method to pull the indicated instance of a complex cell into the indicated parent cell.
* @param inst instance to be pulled up.
* @param cell parent cell.
*/
private String pullInst(SCNiTree inst, SCCell cell)
{
SCCell subCell = (SCCell)inst.np;
// first create components
for (SCNiTree subInst : subCell.niList)
{
if (subInst.type != SPECIALCELL)
{
List<String> createPars = new ArrayList<String>();
createPars.add("create");
createPars.add("instance");
createPars.add(inst.name + "." + subInst.name);
if (subInst.type == LEAFCELL)
{
createPars.add(((Cell)subInst.np).getName());
} else
{
createPars.add(((SCCell)subInst.np).name);
}
String err = create(createPars);
if (err != null) return err;
}
}
// create connections among these subinstances by using the
// subCell's extracted node list. Also resolve connections
// to the parent cell instances by using exported port info.
for (ExtNode eNode = subCell.exNodes; eNode != null; eNode = eNode.next)
{
ExtNode bNode = null;
// check if the extracted node is an exported node
for (SCNiPort iPort = inst.ports; iPort != null; iPort = iPort.next)
{
if (((SCPort)(iPort.port)).node.ports.extNode == eNode)
{
bNode = iPort.extNode;
break;
}
}
if (bNode == null)
{
// this is a new internal node
bNode = new ExtNode();
bNode.name = null;
bNode.firstPort = null;
bNode.ptr = null;
bNode.flags = 0;
bNode.next = cell.exNodes;
cell.exNodes = bNode;
}
// add ports to extracted node bNode
for (ExtPort ePort = eNode.firstPort; ePort != null; ePort = ePort.next)
{
// only add leaf cells or complex cells
if (ePort.node.type != SPECIALCELL)
{
ExtPort nport = new ExtPort();
nport.node = findNi(cell, inst.name + "." + ePort.node.name);
// add reference to extracted node to instance port list
for (SCNiPort iPort = nport.node.ports; iPort != null; iPort = iPort.next)
{
if (iPort.port == ePort.port.port)
{
nport.port = iPort;
iPort.extNode = bNode;
nport.next = bNode.firstPort;
bNode.firstPort = nport;
break;
}
}
}
}
}
// add power ports for new instances
for (ExtPort ePort = subCell.power.firstPort; ePort != null; ePort = ePort.next)
{
if (ePort.node.type == SPECIALCELL) continue;
ExtPort nport = new ExtPort();
nport.node = findNi(cell, inst.name + "." + ePort.node.name);
// add reference to extracted node to instance port list
SCNiPort iPort;
for (iPort = nport.node.ports; iPort != null; iPort = iPort.next)
{
if (iPort.port == ePort.port.port)
{
nport.port = iPort;
iPort.extNode = cell.power;
break;
}
}
if (iPort == null)
{
for (iPort = nport.node.power; iPort != null; iPort = iPort.next)
{
if (iPort.port == ePort.port.port)
{
nport.port = iPort;
iPort.extNode = cell.power;
break;
}
}
}
nport.next = cell.power.firstPort;
cell.power.firstPort = nport;
}
// remove references to original instance in power list
ExtPort nPort = cell.power.firstPort;
for (ExtPort ePort = cell.power.firstPort; ePort != null; ePort = ePort.next)
{
if (ePort.node == inst)
{
if (ePort == nPort)
{
cell.power.firstPort = ePort.next;
nPort = ePort.next;
} else
{
nPort.next = ePort.next;
}
} else
{
nPort = ePort;
}
}
// add ground ports
for (ExtPort ePort = subCell.ground.firstPort; ePort != null; ePort = ePort.next)
{
if (ePort.node.type == SPECIALCELL) continue;
nPort = new ExtPort();
nPort.node = findNi(cell, inst.name + "." + ePort.node.name);
// add reference to extracted node to instance port list
SCNiPort iPort;
for (iPort = nPort.node.ports; iPort != null; iPort = iPort.next)
{
if (iPort.port == ePort.port.port)
{
nPort.port = iPort;
iPort.extNode = cell.ground;
break;
}
}
if (iPort == null)
{
for (iPort = nPort.node.ground; iPort != null; iPort = iPort.next)
{
if (iPort.port == ePort.port.port)
{
nPort.port = iPort;
iPort.extNode = cell.ground;
break;
}
}
}
nPort.next = cell.ground.firstPort;
cell.ground.firstPort = nPort;
}
// remove references to original instance in ground list
nPort = cell.ground.firstPort;
for (ExtPort ePort = cell.ground.firstPort; ePort != null; ePort = ePort.next)
{
if (ePort.node == inst)
{
if (ePort == nPort)
{
cell.ground.firstPort = ePort.next;
nPort = ePort.next;
} else
{
nPort.next = ePort.next;
}
} else
{
nPort = ePort;
}
}
// remove references to instance in exported node list
for (ExtNode eNode = cell.exNodes; eNode != null; eNode = eNode.next)
{
nPort = eNode.firstPort;
for (ExtPort ePort = eNode.firstPort; ePort != null; ePort = ePort.next)
{
if (ePort.node == inst)
{
if (ePort == nPort)
{
eNode.firstPort = ePort.next;
nPort = ePort.next;
} else
{
nPort.next = ePort.next;
}
} else
{
nPort = ePort;
}
}
}
// find the value of the largest generically named extracted node
int oldNum = 0;
for (ExtNode eNode = cell.exNodes; eNode != null; eNode = eNode.next)
{
if (eNode.name != null)
{
int sPtr = 0;
char firstCh = eNode.name.charAt(0);
if (Character.toUpperCase(firstCh) == 'N')
{
sPtr++;
while (sPtr < eNode.name.length())
{
if (!Character.isDigit(eNode.name.charAt(sPtr))) break;
sPtr++;
}
if (sPtr >= eNode.name.length())
{
int newnum = TextUtils.atoi(eNode.name.substring(1));
if (newnum > oldNum)
oldNum = newnum;
}
}
}
}
// set the name of any unnamed nodes
for (ExtNode eNode = cell.exNodes; eNode != null; eNode = eNode.next)
{
if (eNode.name == null)
{
eNode.name = "n" + (++oldNum);
}
}
// flatten any subinstances which are also complex cells
for (SCNiTree subInst : subCell.niList)
{
if (subInst.type == COMPLEXCELL)
{
SCNiTree ninst = findNi(cell, inst.name + "." + subInst.name);
String err = pullInst(ninst, cell);
if (err != null) return err;
}
}
return null;
}
//
// /***********************************************************************
// Module: Sc_extract_print_nodes
// ------------------------------------------------------------------------
// Description:
// Print the common nodes found.
// ------------------------------------------------------------------------
// */
//
// void Sc_extract_print_nodes(SCCell *vars)
// {
// int i;
// ExtNode *simNode;
// ExtPort *pList;
// CHAR *portname;
//
// i = 0;
// if (vars->ground)
// {
// ttyputmsg(M_("Node %d %s:"), i, vars->ground->name);
// for (pList = vars->ground->firstPort; pList; pList = pList->next)
// {
// switch (pList->node->type)
// {
// case SPECIALCELL:
// portname = M_("Special");
// break;
// case COMPLEXCELL:
// portname = ((SCPort *)(pList->port->port))->name;
// break;
// case LEAFCELL:
// portname = Sc_leaf_port_name(pList->port->port);
// break;
// default:
// portname = M_("Unknown");
// break;
// }
// ttyputmsg(x_(" %-20s %s"), pList->node->name, portname);
// }
// }
// i++;
//
// if (vars->power)
// {
// ttyputmsg(M_("Node %d %s:"), i, vars->power->name);
// for (pList = vars->power->firstPort; pList; pList = pList->next)
// {
// switch (pList->node->type)
// {
// case SPECIALCELL:
// portname = M_("Special");
// break;
// case COMPLEXCELL:
// portname = ((SCPort *)(pList->port->port))->name;
// break;
// case LEAFCELL:
// portname = Sc_leaf_port_name(pList->port->port);
// break;
// default:
// portname = M_("Unknown");
// break;
// }
// ttyputmsg(x_(" %-20s %s"), pList->node->name, portname);
// }
// }
// i++;
//
// for (simNode = vars->exNodes; simNode; simNode = simNode->next)
// {
// ttyputmsg(M_("Node %d %s:"), i, simNode->name);
// for (pList = simNode->firstPort; pList; pList = pList->next)
// {
// switch (pList->node->type)
// {
// case SPECIALCELL:
// portname = M_("Special");
// break;
// case COMPLEXCELL:
// portname = ((SCPort *)(pList->port->port))->name;
// break;
// case LEAFCELL:
// portname = Sc_leaf_port_name(pList->port->port);
// break;
// default:
// portname = M_("Unknown");
// break;
// }
// ttyputmsg(x_(" %-20s %s"), pList->node->name, portname);
// }
// i++;
// }
// }
//
/**
* Method to collect the unconnected ports and create an extracted node for each.
*/
private void extractCollectUnconnected(SCCell cell)
{
for (SCNiTree nPtr : cell.niList)
{
// process node
switch (nPtr.type)
{
case COMPLEXCELL:
case LEAFCELL:
for (SCNiPort port = nPtr.ports; port != null; port = port.next)
{
if (port.extNode == null)
{
ExtNode ext = new ExtNode();
ext.name = null;
ExtPort ePort = new ExtPort();
ePort.node = nPtr;
ePort.port = port;
ePort.next = null;
ext.firstPort = ePort;
ext.flags = 0;
ext.ptr = null;
ext.next = cell.exNodes;
cell.exNodes = ext;
port.extNode = ext;
}
}
break;
default:
break;
}
}
}
/**
* Method to return the type of the leaf port.
* @param leafPort pointer to leaf port.
* @return type of port.
*/
static int getLeafPortType(Export leafPort)
{
if (leafPort.isPower()) return PWRPORT;
if (leafPort.isGround()) return GNDPORT;
if (leafPort.getCharacteristic() == PortCharacteristic.BIDIR) return BIDIRPORT;
if (leafPort.getCharacteristic() == PortCharacteristic.OUT) return OUTPORT;
if (leafPort.getCharacteristic() == PortCharacteristic.IN) return INPORT;
return UNPORT;
}
/**
* Method to return the directions that a port can be attached to.
* Values can be up, down, left, right.
*/
static int getLeafPortDirection(PortProto port)
{
return PORTDIRUP | PORTDIRDOWN;
}
}