/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: VerilogReader.java
* Input/output tool: reader for Verilog output (.v)
* Written by Gilda Garreton, Sun Microsystems.
*
* Copyright (c) 2006, 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.io.input.verilog;
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.id.CellId;
import com.sun.electric.database.prototype.PortCharacteristic;
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.technology.ArcProto;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
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.io.input.Input;
import com.sun.electric.tool.placement.Placement;
import com.sun.electric.tool.simulation.SimulationTool;
import com.sun.electric.tool.user.IconParameters;
import com.sun.electric.tool.user.ViewChanges;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.Orientation;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
public class VerilogReader extends Input<Object>
{
List<NodeInst> transistors = new ArrayList<NodeInst>();
double maxWidth = 100, nodeWidth = 10;
double primitiveHeight = 0.5, primitiveWidth = 0.5;
Map<Cell, Point2D.Double> locationMap = new HashMap<Cell, Point2D.Double>();
PrimitiveNode essentialBounds = Generic.tech().findNodeProto("Essential-Bounds");
Cell topCell = null;
Map<String, NodeInst> pinsMap = new HashMap<String, NodeInst>();
private String typicalSkipStrings = "\t\\"; // strings that should be ignored by the StringTokenizer()
private VerilogPreferences localPrefs;
public static class VerilogPreferences extends InputPreferences
{
public boolean runPlacement = SimulationTool.getFactoryVerilogRunPlacementTool();
Placement.PlacementPreferences placementPrefs;
IconParameters iconParameters = IconParameters.makeInstance(true);
public VerilogPreferences(boolean factory)
{
super(factory);
if (!factory)
runPlacement = SimulationTool.getVerilogRunPlacementTool();
// need to cache placement preference here even though it might not be used later
placementPrefs = new Placement.PlacementPreferences(factory);
}
@Override
public Library doInput(URL fileURL, Library lib, Technology tech, Map<Library,Cell> currentCells, Map<CellId,BitSet> nodesToExpand, Job job)
{
VerilogReader in = new VerilogReader(this);
if (in.openTextInput(fileURL)) return null;
lib = in.importALibrary(lib, tech, currentCells);
// running placement tool if selected
if (lib != null && runPlacement)
{
Placement.placeCellNoJob(currentCells.get(lib), placementPrefs);
}
in.closeInput();
return lib;
}
}
/**
* Creates a new instance of VerilogReader.
*/
public VerilogReader(VerilogPreferences ap) { localPrefs = ap; }
private String readCellHeader(List<String> inputs) throws IOException
{
for (;;)
{
String key = getAKeyword();
if (key == null)
{
throw new IOException("Error on line " + lineReader.getLineNumber());
}
StringTokenizer parse = new StringTokenizer(key, "( ),\t", false);
while (parse.hasMoreTokens())
{
String value = parse.nextToken();
if (value.equals(";")) // done with header
return null;
inputs.add(value);
}
}
}
// private static class CellInstance
// {
// String name;
// List<PortInfo> list = new ArrayList<PortInfo>();
//
// CellInstance(String n)
// {
// this.name = TextUtils.correctName(n, false, true);
// }
// static class PortInfo
// {
// String local;
// boolean isBus;
// PortProto ex;
//
// PortInfo(String local, boolean isBus, PortProto ex)
// {
// // Doesn't correct name if it is a bus
// this.local = (isBus) ? local : TextUtils.correctName(local, false, true);
// this.isBus = isBus;
// this.ex = ex;
// }
// }
//
// void addConnection(String local, boolean isBus, PortProto ex)
// {
// PortInfo port = new PortInfo(local, isBus, ex);
// list.add(port);
// }
// }
// private void createInstance(Cell parent, VerilogData verilogData,
// VerilogData.VerilogModule module, Cell icon, CellInstance info)
// {
// NodeInst cellInst = NodeInst.newInstance(icon, getNextLocation(parent), 10, 10, parent,
// Orientation.IDENT, info.name, 0);
//
// List<String> localPorts = new ArrayList<String>();
//
// for (CellInstance.PortInfo port : info.list)
// {
// localPorts.clear();
//
// String portLocal = port.local;
//
// // It is unknown how many pins are coming in the stream
// if (portLocal.contains("{"))
// {
// StringTokenizer parse = new StringTokenizer(portLocal, "{,}", false); // extracting pins
// while (parse.hasMoreTokens())
// {
// String name = parse.nextToken();
// name = name.replaceAll(" ", "");
// localPorts.add(name);
// }
// }
// else
// localPorts.add(portLocal);
//
// for (String s : localPorts)
// {
// NodeInst pin = pinsMap.get(s);
//
// if (pin == null)
// {
// int index = s.indexOf("[");
// if (index != -1)
// {
// s = s.substring(0, index);
// pin = pinsMap.get(s);
// }
// }
//
// if (pin == null)
// {
// if (s.equals("vss")) // ground
// {
// pin = readSupply(module, false, s);
// }
// else
// {
// if (Job.getDebug())
// System.out.println("Unknown signal " + s + " in cell " + parent.describe(false));
// PrimitiveNode primitive = (port.isBus) ? Schematics.tech().busPinNode : Schematics.tech().wirePinNode;
// pin = NodeInst.newInstance(primitive, getNextLocation(parent),
// primitiveWidth, primitiveHeight,
//// primitive.getDefWidth(), primitive.getDefHeight(),
// parent, Orientation.IDENT, null/*s*/, 0);
// pinsMap.put(s, pin);
// }
// }
//
//// ArcProto node = (port.isBus) ? Schematics.tech.bus_arc : Schematics.tech.wire_arc;
// ArcProto node = (pin.getProto() == Schematics.tech().busPinNode) ? Schematics.tech().bus_arc : Schematics.tech().wire_arc;
// PortInst ex = cellInst.findPortInst(port.ex.getName());
// ArcInst ai = ArcInst.makeInstanceBase(node, 0.0,
//// ArcInst ai = ArcInst.makeInstanceFull(node, 0.0 /*node.getDefaultLambdaFullWidth()*/,
// pin.getOnlyPortInst(), ex, null, null, s);
// assert(ai != null);
// ai.setFixedAngle(false);
// }
// }
// }
private NodeInst readSupply(VerilogData.VerilogModule module, boolean power, String name)
{
VerilogData.VerilogPort supply = module.addPort(name, false, false);
supply.type = (power) ? PortCharacteristic.PWR : PortCharacteristic.GND;
return null;
}
private void readInstance(VerilogData.VerilogModule module,
VerilogData.VerilogModule element) throws IOException
{
StringBuffer signature = new StringBuffer();
List<String> exports = new ArrayList<String>();
List<String> pins = new ArrayList<String>();
for (;;)
{
String key = getRestOfLine();
if (key.contains("//")) continue; // comment
signature.append(key);
if (key.contains(";")) // found end of signature
{
String line = signature.toString();
int index = line.indexOf("("); // searching for first (
String instanceName = element.getName() + "-instance";
// if index==0, no name provided -> name is null
assert(index > -1); // do we have cases with -1?
if (index > 0)
{
instanceName = line.substring(0, index);
}
line = line.substring(index+1, line.length());
StringTokenizer parse = new StringTokenizer(line, ")", false); //typicalSkipStrings can't be used
exports.clear(); pins.clear();
while (parse.hasMoreTokens())
{
String value = parse.nextToken();
value = value.replaceAll(" ", "");
index = value.indexOf("."); // look for first .
if (index == -1) // end of tokens
continue; // or break?
int index2 = value.indexOf("("); // look for first (
assert(index2 != -1);
String n = value.substring(index+1, index2);
n = TextUtils.correctName(n, false, true);
// int index3 = n.indexOf("\\"); // those \ are a problem!
// if (index3 != -1)
// n = n.substring(index3+1);
exports.add(n);
n = value.substring(index2+1);
n = TextUtils.correctName(n, false, false);
if (n.contains(" "))
assert(false); // get rid of those empty sapces?
// pins.add(value.substring(index2+1));
pins.add(n);
}
// remove extra white spaces
instanceName = TextUtils.correctName(instanceName, false, true);
instanceName = instanceName.replaceAll(" ", "");
// CellInstance localCell = new CellInstance(instanceName);
VerilogData.VerilogInstance verilogInst = null;
verilogInst = module.addInstance(instanceName, element);
for (int i = 0; i < exports.size(); i++)
{
String export = exports.get(i);
String pin = pins.get(i);
pin = pin.replaceAll(" ", "");
export = export.replaceAll(" ", "");
VerilogData.VerilogPort exp = element.findPort(export);
// fixing original export if not found
if (exp == null)
{
// System.out.println("Warning: port " + export + " not found in module " + element.name + " yet");
exp = element.addPort(export, false, true);
}
verilogInst.addPortInstance(pin, exp);
}
return;
}
}
// never reach this point
}
private String readWiresAndSupplies(VerilogData.VerilogModule module,
boolean readWires, boolean power) throws IOException
{
List<String> values = new ArrayList<String>(2);
for (;;)
{
String input = getRestOfLine();
StringTokenizer parse = new StringTokenizer(input, ",;", true); // net1, net2, [9:0] net4;
while (parse.hasMoreTokens())
{
String net = parse.nextToken();
if (net.equals(",")) continue;
if (net.equals(";"))
{
return null; // done
}
if (readWires) // wires
{
StringTokenizer p = new StringTokenizer(net, typicalSkipStrings+" ", false);
values.clear(); // clean reset
while (p.hasMoreTokens())
{
values.add(p.nextToken());
}
int size = values.size();
if (size == 0) continue;
assert(size == 1 || size == 2);
// PrimitiveNode primitive = Schematics.tech().wirePinNode;
String pinName = values.get(size-1);
int[] vals = {0, 0};
int count = 0;
if (values.size() == 2)
{
p = new StringTokenizer(values.get(0), "[:]", false);
while (p.hasMoreTokens())
{
String s = p.nextToken();
if (TextUtils.isANumber(s))
vals[count++] = Integer.parseInt(s);
}
if (count == 2 && vals[0] != vals[1]) // only if it is a real bus
{
// pinName += values.get(0);
// primitive = Schematics.tech().busPinNode;
}
else
System.out.println(net + " is not a bus wire");
}
pinName = TextUtils.correctName(pinName, false, true);
// also considering [x:x]. Not doing the exception here as above
module.addWire(pinName, (values.size() == 2) ? values.get(0) : null);
}
else // supplies
{
StringTokenizer p = new StringTokenizer(net, "\t ", false);
String name = p.nextToken();
name = TextUtils.correctName(name, false, true);
readSupply(module, power, name); // supply1 -> vdd, supply0 -> gnd or vss
}
}
}
// never reach this point
}
/**
* Method to ignore certain amount of lines. Useful for begin/end blocks and tables
* @param endString
* @param nestedLoop
* @throws IOException
*/
private void ignoreUntilEndOfStatement(String endString, int nestedLoop) throws IOException
{
String key = (endString != null) ? endString : ";"; // endString != null for table for example
for (;;)
{
String input = getRestOfLine();
if (/*endString == null &&*/ input.contains("begin")) // swtch to end only if it is not a table
{
//key = "end";
// ignore the next nested loop
ignoreUntilEndOfStatement("end", nestedLoop+1);
if (nestedLoop == 0)
return; // stop in the outest loop
}
if (input.contains(key))
return; // finish
}
}
private String readInputOutput(VerilogData.VerilogModule module,
PortCharacteristic portType) throws IOException
{
for (;;)
{
String input = getRestOfLine();
if (!input.contains(";"))
{
// doesn't contain proper end of line
String msg = "Missing end of line character ';' in input/output'" + input + "'";
System.out.println(msg);
throw new IOException(msg);
}
StringTokenizer parse = new StringTokenizer(input, ";,", true); // extracting only input name
while (parse.hasMoreTokens())
{
String net = parse.nextToken();
if (net.equals(","))
continue;
if (net.equals(";"))
{
return null; // done
}
StringTokenizer p = new StringTokenizer(net, " \t", false); // extracting only input name
List<String> l = new ArrayList<String>(2);
while (p.hasMoreTokens())
{
String name = p.nextToken();
l.add(name); // it could be "input a;" or "input [9:0] a;"
}
// PrimitiveNode primitive = Schematics.tech().wirePinNode;
int size = l.size();
if (size == 0) continue;
assert(size == 1 || size == 2);
String name = l.get(size - 1);
if (l.size() == 2) // "input a[];"
{
// name += l.get(0); busPin not longer containing [x:y]
// primitive = Schematics.tech().busPinNode;
}
VerilogData.VerilogPort export = module.findPort(name);
// input a, b, c, d, c got problems to parse
if (Job.getDebug())
{
System.out.println("Error: export name '" + name + " 'doesn't match with module signature");
// assert(export != null);
}
if (export != null)
{
// except for clk!!
if (export.type != PortCharacteristic.UNKNOWN && export.type != portType)
System.out.println("Inconsistency in asigning port type in " + name + ". Found " + portType +
" and was " + export.type);
// else
export.type = portType;
if (l.size() == 2)
export.setBusInformation(l.get(0));
}
}
}
// never reach this point
}
private String readCell(VerilogData verilogData, boolean primitive) throws IOException
{
List<String> inputs = new ArrayList<String>(10);
readCellHeader(inputs);
String cellName = inputs.get(0);
VerilogData.VerilogModule module = null;
Cell cell = null;
module = verilogData.getModule(cellName);
if (module == null)
module = verilogData.addModule(cellName, primitive, true);
module.setValid(true);
// adding ports in modules: from 1 -> inputs.size()-1;
for (int i = 1; i < inputs.size(); i++)
module.addPort(inputs.get(i), true, true);
String nextToken = null;
for (;;)
{
String key = null;
if (nextToken != null) // get last token read by network section
{
key = nextToken;
nextToken = null;
}
else
key = getAKeyword();
if (key == null)
{
String msg = "Reach end of file without finding a valid key, i.e. end of a comment";
System.out.println(msg);
throw new IOException(msg);
}
if (key.startsWith("/*"))
{
// read until */ is found
getRestOfComment();
continue;
}
if (key.startsWith("/")) // comment like //
{
getRestOfLine();
continue;
}
if (key.startsWith("endmodule") || key.startsWith("endprimitive"))
{
// done with this cell
return null;
}
if (key.equals("wire"))
{
readWiresAndSupplies(module, true, false);
continue;
}
if (key.startsWith("tri"))
assert(false); // not implemented
if (key.equals("input"))
{
readInputOutput(module, PortCharacteristic.IN);
continue;
}
if (key.equals("output"))
{
readInputOutput(module, PortCharacteristic.OUT);
continue;
}
if (key.equals("inout"))
{
readInputOutput(module, PortCharacteristic.BIDIR);
continue;
}
if (key.startsWith("supply"))
{
boolean power = key.contains("supply1");
readWiresAndSupplies(module, false, power);
continue;
}
// ignoring some elements
if (key.equals("assign") || key.startsWith("always") || key.startsWith("initial")
|| key.startsWith("reg") || key.startsWith("table") || key.startsWith("specify")
|| key.startsWith("begin"))
{
if (Job.getDebug())
System.out.println("Ignoring " + key);
String endStatement = null;
int nestedLoopAllowed = 0;
if (key.startsWith("table"))
endStatement = "endtable";
else if (key.startsWith("specify"))
endStatement = "endspecify";
else if (key.startsWith("always")) // It is always defined in a begin-end block
endStatement = "end";
ignoreUntilEndOfStatement(endStatement, nestedLoopAllowed); // either ; or end
continue;
}
if (key.equals("tranif1")) // transistors
{
// reading gates
//tranif1 nmos4p_0(gnd, gnd, vPlt); -> nmos
assert(false); // implement again
nextToken = readGate(cell, PrimitiveNode.Function.TRANMOS);
continue;
}
if (key.equals("tranif0")) // transistors
{
// reading gates
//tranif1 nmos4p_0(gnd, gnd, vPlt); -> nmos
assert(false); // implement again
nextToken = readGate(cell, PrimitiveNode.Function.TRAPMOS);
continue;
}
// reading cell instances
VerilogData.VerilogModule element = verilogData.getModule(key);
if (element == null) // it hasn't been created
{
element = verilogData.addModule(key, false, false); // assuming latches and other elements are treat as subcells
}
readInstance(module, element);
}
// not reaching this point.
}
/**
* Method to get next X,Y position of the NodeInst in matrix. It also increments the counter for the next elements.
* @return Point2D.Double represeting the NodeInst location
*/
private Point2D.Double getNextLocation(Cell cell)
{
Point2D.Double point = locationMap.get(cell);
double xPos = 0, yPos = 0;
if (point != null) // first time
{
xPos = point.getX();
yPos = point.getY();
}
double x = xPos*nodeWidth, y = yPos*nodeWidth;
Point2D.Double p = new Point2D.Double(x, y);
if (x > maxWidth)
{
yPos++; xPos = 0;
}
else
xPos++;
point = new Point2D.Double(xPos, yPos);
locationMap.put(cell, point); // storing data for next node in cell
return p;
}
/**
* Method to read gate information including ports
* @param cell
* @param function
* @return Next string to evaluate
*/
private String readGate(Cell cell, PrimitiveNode.Function function) throws IOException
{
String input = getRestOfLine();
StringTokenizer parse = new StringTokenizer(input, "(;, \t)", false); // extracting only input name
List<String> list = new ArrayList<String>(2);
while (parse.hasMoreTokens())
{
String value = parse.nextToken();
list.add(value) ;
}
Orientation orient = Orientation.fromAngle(900);
// String gateName = list.get(0);
double width = Schematics.tech().transistorNode.getDefWidth();
double height = Schematics.tech().transistorNode.getDefHeight();
Point2D p = getNextLocation(cell);
NodeInst ni = NodeInst.newInstance(Schematics.tech().transistorNode, p, width, height,
cell, orient, null /*gateName*/);
Schematics.tech().transistorNode.getTechnology().setPrimitiveFunction(ni, function);
transistors.add(ni);
PortInst[] ports = new PortInst[3];
int count = 0;
for (Iterator<PortInst> it = ni.getPortInsts(); it.hasNext();)
{
ports[count++] = it.next();
}
for (int i = 1; i < list.size(); i++)
{
// Gate is the first port, then source and the last one is drain
String name = list.get(i);
// NodeInst pin = cell.findNode(name);
// if pin already exists, the name will be composed
// String pinName = (pin!=null) ? gateName+"-"+name : name;
// parse = new StringTokenizer(name, "[", false); // extracting possible bus name
// String realName = parse.nextToken();
// NodeInst pin = cell.findNode(realName);
// boolean wirePin = (name.equals(realName));
// assert(pin != null);
int pos = (3 + i) % 3; // the first port in g in Electric primitive which is the last (control) port in Verilog
double posX = p.getX(), posY = p.getY();
switch (pos)
{
case 0: // gnd
posX -= width/2;
break;
case 1: // source
posX += width/2; posY -= height/2;
break;
case 2: // drain
posX += width/2; posY += height/2;
break;
}
PrimitiveNode primitive = Schematics.tech().wirePinNode;
ni = NodeInst.newInstance(primitive, new Point2D.Double(posX, posY),
primitiveWidth /*primitive.getDefWidth()*/, primitiveHeight /*primitive.getDefHeight()*/,
cell, Orientation.IDENT, null /*pinName*/);
ArcInst.makeInstanceBase(Schematics.tech().wire_arc, 0.0,
ni.getOnlyPortInst(), ports[pos], null, null, name);
}
return null;
}
/**
* Method to import a Verilog file from disk.
* @param lib the library to ready
* @param currentCells this map will be filled with currentCells in Libraries found in library file
* @return the created library (null on error).
*/
@Override
protected Library importALibrary(Library lib, Technology tech, Map<Library,Cell> currentCells)
{
initKeywordParsing();
VerilogData verilogData = parseVerilogInternal(lib.getName(), true);
buildCells(verilogData, lib, true);
topCell = verilogData.getTopSchematicCell();
if (topCell != null)
{
currentCells.put(topCell.getLibrary(), topCell);
return topCell.getLibrary();
}
return null;
}
public VerilogData parseVerilog(String[] lines, String verilogName)
{
if (openStringsInput(lines))
{
System.out.println("Cannot open string set " + verilogName + " as Verilog");
return null;
}
System.out.println("Reading Verilog format " + verilogName);
initKeywordParsing();
setProgressValue(0);
setProgressNote("Reading Verilog format " + verilogName);
VerilogData verilogData = parseVerilogInternal(verilogName, true);
System.out.println("Verilog format " + verilogName + " read");
return verilogData;
}
/**
* Function to parse Verilog file without creating Electric objects.
* @param file
* @param simplifyWires
* @return VerilogData object
*/
public VerilogData parseVerilog(String file, boolean simplifyWires)
{
URL fileURL = TextUtils.makeURLToFile(file);
if (openTextInput(fileURL))
{
System.out.println("Cannot open the Verilog file: " + file);
return null;
}
System.out.println("Reading Verilog file: " + file);
initKeywordParsing();
setProgressValue(0);
setProgressNote("Reading Verilog file:" + file);
VerilogData verilogData = parseVerilogInternal(file, simplifyWires);
System.out.println("Verilog file: " + file + " read");
return verilogData;
}
public void createCellsOnly(VerilogData verilogData, Job job)
{
Library library = Library.newInstance(verilogData.name, null);
// String topCellName = TextUtils.getFileNameWithoutExtension(verilogData.name, true);
buildCells(verilogData, library, false);
// Cell theCell = library.findNodeProto(topCellName);
if (job != null)
System.out.println("Accumulative time after creating cells '" + verilogData.name + "' " + job.getInfo());
// return theCell; // still work because VerilogReader remembers the top cell
}
public VerilogData readVerilogOnly(String file, boolean fullOyster, Job job)
{
VerilogData verilogData = parseVerilog(file, fullOyster);
if (verilogData == null) return null; // error
if (job != null)
System.out.println("Accumulative time before creating cells '" + file + "' " + job.getInfo());
return verilogData;
}
public Cell readVerilog(String testName, String file, boolean createCells, boolean simplifyWires, Job job)
{
// URL fileURL = TextUtils.makeURLToFile(file);
VerilogData verilogData = parseVerilog(file, simplifyWires);
if (verilogData == null) return null; // error
int index = file.lastIndexOf("/");
String libName = file.substring(index+1);
if (job != null)
System.out.println("Accumulative time before creating cells '" + testName + "' " + job.getInfo());
// Last verilogName must be the top one
if (createCells)
{
Library library = Library.newInstance(libName, null);
// String topCellName = TextUtils.getFileNameWithoutExtension(fileURL);
buildCells(verilogData, library, simplifyWires);
topCell = verilogData.getTopSchematicCell();
if (topCell == null)
{
System.out.println("Check this case in readVerilog"); // is it relevant?
}
}
if (job != null)
System.out.println("Accumulative time after creating cells '" + testName + "' " + job.getInfo());
return topCell; // still work because VerilogReader remembers the top cell
}
private VerilogData parseVerilogInternal(String fileName, boolean simplifyWires)
{
VerilogData verilogData = new VerilogData(fileName);
try
{
String nextToken = null;
String key = null;
for(;;)
{
if (nextToken != null) // get last token read by network section
{
key = nextToken;
nextToken = null;
}
else
key = getAKeyword();
if (key == null) break; // end of the file
if (key.startsWith("/"))
{
getRestOfLine();
continue; // comments
}
if (key.equals("module") || key.equals("primitive"))
{
boolean primitive = key.equals("primitive");
nextToken = readCell(verilogData, primitive);
}
}
} catch (IOException e)
{
System.out.println("Error reading Verilog file: " + e.getMessage());
}
// Simplify wires?: a[1], a[2], a[3] -> a[1:3]
if (simplifyWires) verilogData.simplifyWires();
return verilogData;
}
/**************************************************************************************************************
* Functions to build Electric cells from VerilogData. Functions are here to simplify the VerilogData class
* and dependent classes
*************************************************************************************************************/
/**
* Function to build cells from a VerilogData object
* @param verilogCell
* @param lib
* @param createIconCells
*/
private void buildCells(VerilogData verilogCell, Library lib, boolean createIconCells)
{
for (VerilogData.VerilogModule module : verilogCell.getModules())
{
// Cell cell =
buildCellFromModule(module, lib, createIconCells);
// if (topCell == null && cell.getLibrary() == lib) // first new
// topCell = cell;
}
}
private void addPins(VerilogData.VerilogConnection port, Cell cell, boolean addExport, boolean fullOyster)
{
PortCharacteristic portType = port.getPortType();
List<String> pinNames = port.getPinNames(fullOyster); // This function controls if busses are split into multi pins
// or as just one element
Collections.sort(pinNames);
for (String pinName : pinNames)
{
PrimitiveNode primitive = Schematics.tech().wirePinNode;
NodeInst ni = cell.findNode(pinName);
if (ni == null)
{
ni = NodeInst.newInstance(primitive, getNextLocation(cell),
primitiveWidth, primitiveHeight,
cell, Orientation.IDENT, pinName);
if (addExport)
{
Export.newInstance(cell, ni.getOnlyPortInst(), pinName, portType);
}
}
else
{
assert(false);
System.out.println("Wire/Input/Output " + pinName + " exists");
}
}
}
/**
* Function to build cell fro a VerilogModule object
* @param lib
* @param createIconcells
* @return Cell object representing this module
*/
private Cell buildCellFromModule(VerilogData.VerilogModule module, Library lib, boolean createIconcells)
{
String cellName = module.name + View.SCHEMATIC.getAbbreviationExtension();
Cell cell = Library.findCellInLibraries(cellName, View.SCHEMATIC, null);
if (cell != null) return cell; // already created;
cell = Cell.makeInstance(lib, cellName);
cell.setTechnology(Schematics.tech());
// Adding essential bounds for now
// Change Sept 08, 07 Out
// NodeInst.makeInstance(essentialBounds, new Point2D.Double(10,10), 1, 1, cell,
// Orientation.IDENT, null, 0);
// NodeInst.makeInstance(essentialBounds, new Point2D.Double(-10,-10), 1, 1, cell,
// Orientation.RR, null, 0);
List<Object> all = module.getAllSorted();
for (Object obj : all)
{
if (obj instanceof VerilogData.VerilogWire)
// wires first to determine which pins are busses or simple pins
// for (VerilogData.VerilogWire wire : module.getWires())
{
VerilogData.VerilogWire wire = (VerilogData.VerilogWire)obj;
addPins(wire, cell, false, createIconcells);
}
else if (obj instanceof VerilogData.VerilogPort)
// inputs/outputs/inouts/supplies
// for (VerilogData.VerilogPort port : module.getPorts())
{
//Point2D center, double width, double height, Cell parent)
VerilogData.VerilogPort port = (VerilogData.VerilogPort)obj;
String name = port.name;
PortCharacteristic portType = port.type;
// input/output/inout
if (portType == PortCharacteristic.BIDIR ||
portType == PortCharacteristic.IN ||
portType == PortCharacteristic.OUT ||
portType == PortCharacteristic.CLK ||
portType == PortCharacteristic.UNKNOWN) // unknown when modules are read as instances
{
// new code
addPins(port, cell, true, createIconcells);
}
else if (portType == PortCharacteristic.PWR ||
portType == PortCharacteristic.GND)
{
boolean power = portType == PortCharacteristic.PWR;
PrimitiveNode np = (power) ? Schematics.tech().powerNode : Schematics.tech().groundNode;
Point2D.Double p = getNextLocation(cell);
double height = primitiveHeight; //np.getDefHeight();
NodeInst supply = NodeInst.newInstance(np, p,
primitiveWidth, height,
cell, Orientation.IDENT, name);
// extra pin
NodeInst ni = NodeInst.newInstance(Schematics.tech().wirePinNode, new Point2D.Double(p.getX(), p.getY()+height/2),
0.5, 0.5,
cell, Orientation.IDENT, name+"@0");
ArcInst.makeInstanceBase(Schematics.tech().wire_arc, 0.0,
ni.getOnlyPortInst(), supply.getOnlyPortInst(), null, null, name);
Export.newInstance(cell, ni.getOnlyPortInst(), name, portType);
}
else
System.out.println("Skipping this characteristic?");
}
}
// instances
for (VerilogData.VerilogInstance inst : module.getInstances())
{
buildNodeInstFromModule(inst, lib, cell, createIconcells);
}
// making icon
if (createIconcells)
ViewChanges.makeIconViewNoGUI(cell, true, true);
return cell; // not too much sense?
}
/**
* Function to build a NodeInst object from a VerilogInstance object
* @param inst
* @param lib
* @param parent
* @param useIconCell
*/
Cell buildNodeInstFromModule(VerilogData.VerilogInstance inst, Library lib, Cell parent, boolean useIconCell)
{
Cell schematics = buildCellFromModule(inst.element, lib, useIconCell);
Cell icon = (useIconCell) ? schematics.iconView() : schematics;
// if (icon == null)
// assert(icon != null);
// Only for benchmarks schematics in
NodeInst cellInst = NodeInst.newInstance(icon, getNextLocation(parent), 10, 10, parent,
Orientation.IDENT, inst.name);
for (VerilogData.VerilogPortInst port : inst.ports)
{
List<String> localPorts = port.getPortNames();
// Start and end are only valid for bus wires/inputs. The pin numbers should be in the order
// they were defined in the port (ascendent or descendent)
int startPort = port.port.start;
int endPort = port.port.end;
int count = startPort;
boolean asc = (startPort < endPort);
for (String s : localPorts)
{
NodeInst pin = parent.findNode(s); // not sure if this should be done per cell or ask
if (pin == null)
{
int index = s.indexOf("[");
if (index != -1)
{
s = s.substring(0, index);
pin = parent.findNode(s);
}
}
if (pin == null)
{
// Still missing vss code?
if (Job.getDebug())
System.out.println("Unknown signal " + s + " in cell " + parent.describe(false));
PrimitiveNode primitive = (port.port.isBusConnection()) ? Schematics.tech().busPinNode : Schematics.tech().wirePinNode;
pin = NodeInst.newInstance(primitive, getNextLocation(parent), primitiveWidth, primitiveHeight,
parent, Orientation.IDENT, /*null*/s); // not sure why it has to be null?
}
ArcProto node = (pin.getProto() == Schematics.tech().busPinNode) ? Schematics.tech().bus_arc : Schematics.tech().wire_arc;
String exportName = port.port.name;
if (port.port.isBusConnection())
{
// add bit so the pin can be found.
exportName += "[" + count + "]";
}
PortInst ex = cellInst.findPortInst(exportName);
assert(ex != null); // it can't work without export. Check this case if fails
ArcInst ai = ArcInst.makeInstanceBase(node, 0.0,
pin.getOnlyPortInst(), ex, null, null, s);
if (ai == null)
assert(ai != null);
ai.setFixedAngle(false);
if (asc) count++;
else count--;
}
}
return schematics;
}
}