/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: VerilogData.java
* Input/output tool: reader for Verilog output (.v)
* Written by Gilda Garreton, Sun Microsystems.
*
* Copyright (c) 2007, 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.Library;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.tool.Job;
import com.sun.electric.util.TextUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
public class VerilogData implements Serializable
{
String name;
private Map<String, VerilogModule> modules = new HashMap<String, VerilogModule>();
private VerilogModule lastModule; // last module read is the top cell info
VerilogData(String name)
{
this.name = name;
}
public String getName() {return name;}
public Cell getTopSchematicCell()
{
String topCellName = TextUtils.getFileNameWithoutExtension(name, true);
String cellName = topCellName + View.SCHEMATIC.getAbbreviationExtension();
Cell top = Library.findCellInLibraries(cellName, View.SCHEMATIC, null);
if (top == null) // found a cell called like the filename
{
// taking the first cell found in module
if (lastModule == null) return null;
top = Library.findCellInLibraries(lastModule.name + View.SCHEMATIC.getAbbreviationExtension(),
View.SCHEMATIC, null);
}
return top;
}
VerilogModule addModule(String name, boolean primitive, boolean definedInFile)
{
VerilogModule module = new VerilogModule(name, primitive);
if (definedInFile) // read from the file, not instance
lastModule = module;
modules.put(name, module);
return module;
}
/**
* Compare class for VerilogModule
*/
private static VerilogModuleSort compareVerilogModules = new VerilogModuleSort();
private static class VerilogModuleSort implements Comparator<VerilogModule>
{
public int compare(VerilogModule a1, VerilogModule a2)
{
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(a1.getName(), a2.getName());
return cmp;
// return (a1.getName().compareTo(a2.getName()));
}
}
/**
* Function to return a collection of modules defined.
* The collection is sorted by name.
* @return Collection of VerilogModule objects
*/
public Collection<VerilogModule> getModules()
{
List<VerilogModule> list = new ArrayList<VerilogModule>(modules.size());
list.addAll(modules.values());
Collections.sort(list, compareVerilogModules);
return list;
}
/**
* Function to return VerilogModule object for a given name
* @param name name of the module
* @return VerilogModule object
*/
VerilogModule getModule(String name) {return modules.get(name);}
/**
* Function to write in standard output the modules in Verilog format
*/
void write()
{
for (VerilogModule module : modules.values())
{
module.write();
}
}
void simplifyWires()
{
for (VerilogModule module : modules.values())
{
module.simplifyWires();
}
}
/********************** AUXILIAR CLASSES *************************************/
/**
* Covers supplies
*/
abstract static class VerilogConnection implements Serializable
{
protected String name;
int start;
int end;
VerilogConnection(String name)
{
this.name = name;
}
/**
* Method to control if busses are converted into single pins or treated as bus in Electric.
* For now, busses are converted into single pins. More memory is used though.
* @return the list of pin names.
* @param fullOyster
*/
abstract List<String> getPinNames(boolean fullOyster);
PortCharacteristic getPortType() {return null; } // not valid
String getName() {return name;}
/**
* Function to know if a wire represents a wire
* @return true if wire is a bus
*/
boolean isBusConnection()
{
return (start != end);
}
String getConnectionName()
{
if (start != -1) // it could be a bus or simple wire
{
if (isBusConnection())
return name + "[" + start + ":" + end + "]";
else
return name + "[" + start + "]";
}
else // simple wire
return name;
}
}
/**
* Compare class for VerilogModule
*/
private static VerilogPortSort compareVerilogPorts = new VerilogPortSort();
private static class VerilogPortSort implements Comparator<VerilogPort>
{
public int compare(VerilogPort a1, VerilogPort a2)
{
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(a1.name, a2.name);
return cmp;
// return (a1.name.compareTo(a2.name));
}
}
/**
* This class covers input/output/inout
*/
public class VerilogPort extends VerilogConnection
{
PortCharacteristic type;
VerilogPort(String name, PortCharacteristic type)
{
super(name);
this.type = type;
start = end = -1;
}
PortCharacteristic getPortType() {return type; } // not valid
void setBusInformation(String s)
{
int pos = s.indexOf(":");
start = Integer.parseInt(s.substring(1, pos)); // first number
end = Integer.parseInt(s.substring(pos+1, s.length()-1)); // second number
}
public List<String> getPinNames(boolean fullOyster)
{
List<String> list = new ArrayList<String>();
if (fullOyster && isBusConnection())
{
extractPinNames(start, end, name, list);
} else
{
list.add(name);
}
return list;
}
void write()
{
String typeName = "";
if (type == PortCharacteristic.BIDIR) typeName = "inout";
else if (type == PortCharacteristic.IN) typeName = "input";
else if (type == PortCharacteristic.OUT) typeName = "output";
else if (type == PortCharacteristic.GND) typeName = "supply0";
else if (type == PortCharacteristic.PWR) typeName = "supply1";
System.out.println("\t" + typeName + " " + ((isBusConnection())?"["+start+":"+end+"]":"") + " " + name + ";");
}
}
/**
* This class covers wires. To avoid confusion, VerilogExport is not used for this type.
*/
public static class VerilogWire extends VerilogConnection
{
public VerilogWire(String name, String busPins)
{
super(name);
this.name = name;
if (busPins == null)
{
int index = name.indexOf("[");
if (index != -1)
{
this.name = name.substring(0, index);
index = Integer.parseInt(name.substring(index+1, name.length()-1));
}
this.start = this.end = index;
}
else
{
int index2 = busPins.indexOf(":");
assert(index2 != -1);
start = Integer.parseInt(busPins.substring(1, index2)); // assuming 0 contains "["
end = Integer.parseInt(busPins.substring(index2+1, busPins.length()-1));
}
}
List<String> getPinNames(boolean fullOyster)
{
List<String> list = new ArrayList<String>();
if (fullOyster && isBusConnection())
{
extractPinNames(start, end, name, list);
} else
{
list.add(name);
}
return list;
}
void write()
{
System.out.println("\twire " + ((start != end)?("["+start+":"+end+"["):"") + " " + name + ";");
}
}
private static void extractPinNames(int start, int end, String root, List<String> l)
{
if (start > end)
{
for (int i = start; i >= end; i--)
{
String thisName = root+"["+i+"]";
l.add(thisName);
}
}
else
{
for (int i = start; i <= end; i++)
{
String thisName = root+"["+i+"]";
l.add(thisName);
}
}
}
public class VerilogPortInst implements Serializable
{
String name;
VerilogPort port;
VerilogPortInst(String name, VerilogPort port)
{
this.name = name;
this.port = port;
}
List<String> getPortNames()
{
List<String> list = new ArrayList<String>();
// It is unknown how many pins are coming in the stream
if (name.contains("{"))
{
StringTokenizer parse = new StringTokenizer(name, "\t{,}", false); // extracting pins
while (parse.hasMoreTokens())
{
String name = parse.nextToken();
name = name.replaceAll(" ", "");
list.add(name);
if (Job.getDebug())
assert(!name.contains(":")); // this case not handled yet!
// else
// System.out.println("This case not handled yet in getPortNames");
}
}
else
list.add(name);
// Now to really extract every individual pin
List<String> l = new ArrayList<String>(list.size());
for (String s : list)
{
int pos = s.indexOf(":");
if (pos != -1)
{
int index1 = s.indexOf("[");
int index2 = s.indexOf("]");
String root = s.substring(0, index1);
int start = Integer.parseInt(s.substring(index1+1, pos)); // first number
int end = Integer.parseInt(s.substring(pos+1, index2)); // second number
extractPinNames(start, end, root, l);
}
else
l.add(s);
}
// sort list
return l;
}
}
/**
* Compare class for VerilogInstance
*/
private static VerilogInstanceSort compareVerilogInstances = new VerilogInstanceSort();
private static class VerilogInstanceSort implements Comparator<VerilogInstance>
{
public int compare(VerilogInstance a1, VerilogInstance a2)
{
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(a1.getName(), a2.getName());
return cmp;
// return (a1.getName().compareTo(a2.getName()));
}
}
public class VerilogInstance implements Serializable
{
String name;
VerilogModule element;
List<VerilogPortInst> ports = new ArrayList<VerilogPortInst>();
// number of ports in the instance doesn't necessarily match with number of ports in original elements.
VerilogInstance(String name, VerilogModule elem)
{
this.name = name;
this.element = elem;
}
/**
* Function to return the name of this instance
* @return String with the name of the instance
*/
public String getName() {return name;}
/**
* Function to return the module of this instance
* @return Verilog object
*/
public VerilogModule getModule() {return element;}
VerilogPortInst addPortInstance(String name, VerilogPort port)
{
VerilogPortInst inst = new VerilogPortInst(name, port);
ports.add(inst);
return inst;
}
void write()
{
System.out.print("\t" + element.name + " " + name + " (");
int size = ports.size();
// assert(size == element.getNumPorts());
for (int i = 0; i < size; i++)
{
VerilogPortInst port = ports.get(i);
System.out.print("." + port.port.name + " (" + port.name + ")");
if (i < size - 1)
System.out.print(", ");
}
System.out.println(");");
}
}
/**
* Compare class for VerilogAll
*/
private static VerilogAllSort compareVerilogAll = new VerilogAllSort();
private static class VerilogAllSort implements Comparator<Object>
{
public int compare(Object a1, Object a2)
{
String name1, name2;
if (a1 instanceof VerilogInstance)
name1 = ((VerilogInstance)a1).getName();
else if (a1 instanceof VerilogWire)
name1 = ((VerilogWire)a1).getName();
else
name1 = ((VerilogPort)a1).getName();
if (a2 instanceof VerilogInstance)
name2 = ((VerilogInstance)a2).getName();
else if (a2 instanceof VerilogWire)
name2 = ((VerilogWire)a2).getName();
else
name2 = ((VerilogPort)a2).getName();
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(name1, name2);
return cmp;
}
}
/**
* Class to represent subcells
*/
public class VerilogModule implements Serializable
{
String name;
boolean fullInfo; // in case the module information was found in the file
private List<VerilogWire> wires = new ArrayList<VerilogWire>();
private Map<String,VerilogPort> ports = new LinkedHashMap<String,VerilogPort>(); // collection of input/output/inout/supply elements, ordering is important
List<VerilogInstance> instances = new ArrayList<VerilogInstance>();
boolean primitive; // if this is a primitive instead of a module
VerilogModule(String name, boolean primitive)
{
this.name = name;
this.fullInfo = false;
}
/**
* Function to mark module as fully read it from the file
* @param flag
*/
void setValid(boolean flag) {fullInfo = flag;}
/**
* Returns if module is valid, i.e., theinformation was 100% read from the file
* @return true if is a valid module
*/
public boolean isValid() {return fullInfo;}
/**
* Function returning the name of the module
* @return String with name of the module
*/
public String getName() {return name;}
/**
* Returns true if this was defined as a 'primitive' instead of
* a 'module'.
* @return true if this module was defined as a primitive
*/
public boolean isPrimitive() { return primitive; }
/**
* Returns list of ports and wires sorted by name
* @return list of ports and wires sorted by namea
*/
public List<Object> getAllSorted() {
List<Object> list = new ArrayList<Object>(ports.size() + wires.size());
list.addAll(ports.values());
list.addAll(wires);
Collections.sort(list, compareVerilogAll);
return list;
}
/**
* Function to return list of VerilogInstance objects in the module.
* The list is sorted.
* @return List of VerilogInstance objects
*/
public List<VerilogInstance> getInstances()
{
Collections.sort(instances, compareVerilogInstances);
return instances;
}
/**
* Function to return list of VerilogWire objects in the module.
* The list is sorted.
* @return List of VerilogWire objects
*/
public List<VerilogWire> getWires()
{
Collections.sort(wires, compareVerilogWires);
return wires;
}
/**
* Function to return collection of VerilogPort objects in the module.
* The ports are sorted by the name
* @return Collection of VerilogPort objects
*/
public Collection<VerilogPort> getPorts()
{
List<VerilogPort> list = new ArrayList<VerilogPort>(ports.size());
list.addAll(ports.values());
Collections.sort(list, compareVerilogPorts);
return list;
}
/**
* Function to search an export for a given name
* @param name export name
* @return VerilogExport represeting the export
*/
VerilogPort findPort(String name)
{
// In case of large set, better if ports are in a map.
return ports.get(name);
}
/**
* Function to add a given export to the list
* @param name name of the new export
* @param checkClock
* @param checkDuplicatedPortName
*/
VerilogPort addPort(String name, boolean checkClock, boolean checkDuplicatedPortName)
{
if (checkDuplicatedPortName && findPort(name) != null)
{
System.out.println("Duplicated port name? " + name);
if (Job.getDebug())
assert(false); // force to take a look
}
PortCharacteristic def = PortCharacteristic.UNKNOWN;
String lowerName = name.toLowerCase();
// attempt to get the type based on port name (in,out)
if (lowerName.startsWith("in"))
def = PortCharacteristic.IN;
else if (lowerName.startsWith("out"))
def = PortCharacteristic.OUT;
// so far having problems to detect clk signals as input. Only done in case of matching
// name from the module input
else if (checkClock && lowerName.endsWith("clk")) //
def = PortCharacteristic.CLK;
VerilogPort export = new VerilogPort(name, def);
ports.put(name, export);
return export;
}
VerilogInstance addInstance(String name, VerilogModule element)
{
VerilogInstance inst = new VerilogInstance(name, element);
instances.add(inst);
return inst;
}
VerilogWire addWire(String name, String busInfo)
{
VerilogData.VerilogWire wire = new VerilogData.VerilogWire(name, busInfo);
wires.add(wire);
return wire;
}
/**
* Function to print information in Verilog format. For testing purposes mainly
*/
void write()
{
System.out.print("module " + name + " (");
Set<String> ports = this.ports.keySet();
int size = ports.size();
int count = 0;
for (String s : ports)
{
System.out.print(s);
if (count < size - 1)
System.out.print(", ");
count++;
}
System.out.println(");");
System.out.println();
// inputs/outputs/inouts/supplies
for (VerilogPort e : this.ports.values())
{
e.write();
}
System.out.println();
// wires
for (VerilogWire w : wires)
{
w.write();
}
// instances
for (VerilogInstance i : instances)
{
i.write();
}
System.out.println("endmodule");
System.out.println();
}
/**
* Simplify wires?: a[1], a[2], a[3] -> a[1:3]
*/
void simplifyWires()
{
Collections.sort(wires, compareVerilogWires);
int i = 0;
List<VerilogWire> toDelete = new ArrayList<VerilogWire>();
while (i < wires.size())
{
VerilogWire w = wires.get(i);
if (w.start == -1)
{
i++;
continue; // nothing to do with this one
}
// searching for all wire pins with identical root name
int j, end = w.end;
List<VerilogWire> toMerge = new ArrayList<VerilogWire>();
// This algorithm doesn't check for overlapping in pin numbers
for (j = i+1; j < wires.size(); j++)
{
VerilogWire r = wires.get(j);
// in case the element is a wire pin abc[x:y]
if (!w.name.equals(r.name))
{
break; // stop here
}
// look for next bit
// if (r.start != end && r.start != end+1)
// break; // stop here
end = r.end;
toMerge.add(r);
}
if (toMerge.size() > 0)
{
// check if pins are conse
toDelete.addAll(toMerge);
w.end = end;
}
i = j;
}
wires.removeAll(toDelete);
}
}
private static VerilogWireSort compareVerilogWires = new VerilogWireSort();
private static class VerilogWireSort implements Comparator<VerilogWire>
{
public int compare(VerilogWire a1, VerilogWire a2)
{
int diff = TextUtils.STRING_NUMBER_ORDER.compare(a1.name, a2.name);
// int diff = (a1.name.compareTo(a2.name));
if (diff == 0) // identical
{
diff = a1.start - a2.start;
if (diff == 0) // try with end pins
{
diff = a1.end - a2.end;
assert(diff!=0); // can't have identical wires
}
}
return (diff);
}
}
}