/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: VerilogOut.java
* Input/output tool: reader for Verilog output (.v)
* Written by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2004 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.io.input.verilog;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.tool.io.input.Simulate;
import com.sun.electric.tool.simulation.DigitalAnalysis;
import com.sun.electric.tool.simulation.DigitalSignal;
import com.sun.electric.tool.simulation.Signal;
import com.sun.electric.tool.simulation.Stimuli;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Class for reading and displaying waveforms from Verilog output.
* These are contained in .v files.
*/
public class VerilogOut extends Simulate
{
private static class VerilogStimuli
{
double time;
int state;
VerilogStimuli(double time, int state)
{
this.time = time;
this.state = state;
}
}
public VerilogOut() {}
/**
* Method to read an Verilog output file.
*/
protected void readSimulationOutput(Stimuli sd, URL fileURL, Cell cell)
throws IOException
{
// open the file
if (openTextInput(fileURL)) return;
// show progress reading .dump file
startProgressDialog("Verilog output", fileURL.getFile());
// read the actual signal data from the .dump file
readVerilogFile(cell, sd);
// stop progress dialog, close the file
stopProgressDialog();
closeInput();
}
private void readVerilogFile(Cell cell, Stimuli sd)
throws IOException
{
DigitalAnalysis an = new DigitalAnalysis(sd, true);
sd.setCell(cell);
double timeScale = 1.0;
String currentScope = "";
int curLevel = 0;
int numSignals = 0;
Map<String,Object> symbolTable = new HashMap<String,Object>();
Map<DigitalSignal,List<VerilogStimuli>> dataMap = new HashMap<DigitalSignal,List<VerilogStimuli>>();
List<DigitalSignal> curArray = null;
for(;;)
{
String keyword = getNextKeyword();
if (keyword == null) break;
// ignore "$date", "$version" or "$timescale"
if (keyword.equals("$date") || keyword.equals("$version"))
{
parseToEnd();
continue;
}
if (keyword.equals("$timescale"))
{
String units = getNextKeyword();
timeScale = TextUtils.atof(units);
if (units.endsWith("ms")) timeScale /= 1000.0; else
if (units.endsWith("us")) timeScale /= 1000000.0; else
if (units.endsWith("ns")) timeScale /= 1000000000.0; else
if (units.endsWith("ps")) timeScale /= 1000000000000.0; else
if (units.endsWith("fs")) timeScale /= 1000000000000000.0;
parseToEnd();
continue;
}
if (keyword.equals("$scope"))
{
String scope = getNextKeyword();
if (scope == null) break;
if (scope.equals("module") || scope.equals("task") || scope.equals("function"))
{
// scan for arrays
cleanUpScope(curArray, an);
curArray = new ArrayList<DigitalSignal>();
String scopeName = getNextKeyword();
if (scopeName == null) break;
if (currentScope.length() > 0) currentScope += ".";
currentScope += scopeName;
curLevel++;
curArray = new ArrayList<DigitalSignal>();
}
parseToEnd();
continue;
}
if (keyword.equals("$upscope"))
{
if (curLevel <= 0 || currentScope.length() == 0)
{
System.out.println("Unbalanced $upscope on line " + lineReader.getLineNumber());
continue;
}
// scan for arrays
cleanUpScope(curArray, an);
curArray = new ArrayList<DigitalSignal>();
int dotPos = currentScope.lastIndexOf('.');
if (dotPos >= 0)
{
currentScope = currentScope.substring(0, dotPos);
curLevel--;
}
parseToEnd();
continue;
}
if (keyword.equals("$var"))
{
String varName = getNextKeyword();
if (varName == null) break;
if (varName.equals("wire") || varName.equals("reg") ||
varName.equals("supply0") || varName.equals("supply1") ||
varName.equals("parameter") || varName.equals("trireg") ||
varName.equals("in") || varName.equals("out") ||
varName.equals("inout"))
{
// get the bus width
String widthText = getNextKeyword();
if (widthText == null) break;
int width = TextUtils.atoi(widthText);
// get the symbol name for this signal
String symbol = getNextKeyword();
if (symbol == null) break;
// get the signal name
String signalName = getNextKeyword();
if (signalName == null) break;
// see if there is an index
String index = getNextKeyword();
if (index == null) break;
if (index.equals("$end")) index = ""; else
{
parseToEnd();
}
numSignals++;
DigitalSignal sig = new DigitalSignal(an);
sig.setSignalName(signalName + index, currentScope);
dataMap.put(sig, new ArrayList<VerilogStimuli>());
if (index.length() > 0 && width == 1)
{
curArray.add(sig);
}
if (width > 1)
{
// create fake signals for the individual entries
sig.setSignalName(signalName + "[0:" + (width-1) + "]", null);
sig.buildBussedSignalList();
for(int i=0; i<width; i++)
{
DigitalSignal subSig = new DigitalSignal(an);
subSig.setSignalName(signalName + "[" + i + "]", currentScope);
dataMap.put(subSig, new ArrayList<VerilogStimuli>());
sig.addToBussedSignalList(subSig);
addSignalToHashMap(subSig, symbol + "[" + i + "]", symbolTable);
numSignals++;
}
}
// put it in the symbol table
addSignalToHashMap(sig, symbol, symbolTable);
}
continue;
}
if (keyword.equals("$enddefinitions"))
{
parseToEnd();
System.out.println("Found " + numSignals + " signal names");
continue;
}
if (keyword.equals("$dumpvars"))
{
double curTime = 0.0;
for(;;)
{
String currentLine = getLineFromSimulator();
if (currentLine == null) break;
char chr = currentLine.charAt(0);
String restOfLine = currentLine.substring(1);
if (chr == '0' || chr == '1' || chr == 'x' || chr == 'X' ||
chr == 'z' || chr == 'Z')
{
Object entry = symbolTable.get(restOfLine);
if (entry == null)
{
System.out.println("Unknown symbol '" + restOfLine + "' on line " + lineReader.getLineNumber());
continue;
}
if (entry instanceof List) entry = ((List)entry).get(0);
DigitalSignal sig = (DigitalSignal)entry;
// insert the stimuli
int state = 0;
switch (chr)
{
case '0': state = Stimuli.LOGIC_LOW | Stimuli.GATE_STRENGTH; break;
case '1': state = Stimuli.LOGIC_HIGH | Stimuli.GATE_STRENGTH; break;
case 'X':
case 'x': state = Stimuli.LOGIC_X | Stimuli.GATE_STRENGTH; break;
case 'Z':
case 'z': state = Stimuli.LOGIC_Z | Stimuli.GATE_STRENGTH; break;
}
VerilogStimuli vs = new VerilogStimuli(curTime, state);
List<VerilogStimuli> listForSig = dataMap.get(sig);
listForSig.add(vs);
continue;
}
if (chr == '$')
{
if (restOfLine.equals("end")) continue;
if (restOfLine.equals("dumpon")) continue;
if (restOfLine.equals("dumpoff")) continue;
if (restOfLine.equals("dumpall")) continue;
System.out.println("Unknown directive on line " + lineReader.getLineNumber() + ": " + currentLine);
continue;
}
if (chr == '#')
{
curTime = TextUtils.atof(restOfLine) * timeScale;
continue;
}
if (chr == 'b')
{
int spacePos = restOfLine.indexOf(' ');
if (spacePos < 0)
{
System.out.println("Bus has missing signal name on line " + lineReader.getLineNumber() + ": " + currentLine);
continue;
}
String symName = restOfLine.substring(spacePos+1);
Object entry = symbolTable.get(symName);
if (entry == null)
{
System.out.println("Unknown symbol '" + symName + "' on line " + lineReader.getLineNumber());
continue;
}
if (entry instanceof List) entry = ((List)entry).get(0);
DigitalSignal sig = (DigitalSignal)entry;
int i = 0;
for(Signal anySig : sig.getBussedSignals())
{
DigitalSignal subSig = (DigitalSignal)anySig;
char bit = restOfLine.charAt(i++);
int state = 0;
switch (bit)
{
case '0': state = Stimuli.LOGIC_LOW | Stimuli.GATE_STRENGTH; break;
case '1': state = Stimuli.LOGIC_HIGH | Stimuli.GATE_STRENGTH; break;
case 'X':
case 'x': state = Stimuli.LOGIC_X | Stimuli.GATE_STRENGTH; break;
case 'Z':
case 'z': state = Stimuli.LOGIC_Z | Stimuli.GATE_STRENGTH; break;
}
VerilogStimuli vs = new VerilogStimuli(curTime, state);
List<VerilogStimuli> listForSig = dataMap.get(subSig);
listForSig.add(vs);
}
continue;
}
System.out.println("Unknown stimulus on line " + lineReader.getLineNumber() + ": " + currentLine);
}
}
continue;
}
// convert the stimuli
for(Object entry : symbolTable.values())
{
List<DigitalSignal> fullList = null;
if (entry instanceof List)
{
fullList = (List)entry;
entry = fullList.get(0);
}
DigitalSignal sig = (DigitalSignal)entry;
List<VerilogStimuli> listForSig = dataMap.get(sig);
int numStimuli = listForSig.size();
if (numStimuli == 0) continue;
sig.buildTime(numStimuli);
sig.buildState(numStimuli);
int i = 0;
for(VerilogStimuli vs : listForSig)
{
sig.setTime(i, vs.time);
sig.setState(i, vs.state);
i++;
}
if (fullList != null)
{
for(DigitalSignal oSig : fullList)
{
if (oSig.getTimeVector() == null) oSig.setTimeVector(sig.getTimeVector());
if (oSig.getStateVector() == null) oSig.setStateVector(sig.getStateVector());
}
}
}
// remove singular top-level signal name (this code also occurs in HSpiceOut.readTRDCACFile)
String singularPrefix = null;
for(Signal sSig : an.getSignals())
{
String context = sSig.getSignalContext();
if (context == null) { singularPrefix = null; break; }
int dotPos = context.indexOf('.');
if (dotPos >= 0) context = context.substring(0, dotPos);
if (singularPrefix == null) singularPrefix = context; else
{
if (!singularPrefix.equals(context)) { singularPrefix = null; break; }
}
}
if (singularPrefix != null)
{
int len = singularPrefix.length();
for(Signal sSig : an.getSignals())
{
String context = sSig.getSignalContext();
if (context == null || context.length() <= len) sSig.setSignalContext(null); else
{
sSig.setSignalContext(context.substring(len+1));
}
}
}
}
private void cleanUpScope(List<DigitalSignal> curArray, DigitalAnalysis an)
{
if (curArray == null) return;
String last = null;
String scope = null;
int firstEntry = 0;
int firstIndex = 0;
int lastIndex = 0;
int numSignalsInArray = curArray.size();
for(int j=0; j<numSignalsInArray; j++)
{
DigitalSignal sig = curArray.get(j);
int squarePos = sig.getSignalName().indexOf('[');
if (squarePos < 0) continue;
String purename = sig.getSignalName().substring(0, squarePos);
int index = TextUtils.atoi(sig.getSignalName().substring(squarePos+1));
if (last == null)
{
firstEntry = j;
last = purename;
firstIndex = lastIndex = index;
scope = sig.getSignalContext();
} else
{
if (last.equals(purename)) lastIndex = index; else
{
DigitalSignal arraySig = new DigitalSignal(an);
arraySig.setSignalName(last + "[" + firstIndex + ":" + lastIndex + "]", scope);
arraySig.buildBussedSignalList();
int width = j - firstEntry;
for(int i=0; i<width; i++)
{
DigitalSignal subSig = curArray.get(firstEntry+i);
arraySig.addToBussedSignalList(subSig);
}
last = null;
}
}
}
if (last != null)
{
DigitalSignal arraySig = new DigitalSignal(an);
arraySig.setSignalName(last + "[" + firstIndex + ":" + lastIndex + "]", scope);
arraySig.buildBussedSignalList();
int width = numSignalsInArray - firstEntry;
for(int i=0; i<width; i++)
{
DigitalSignal subSig = curArray.get(firstEntry+i);
arraySig.addToBussedSignalList(subSig);
}
}
}
private void addSignalToHashMap(DigitalSignal sig, String symbol, Map<String,Object> symbolTable)
{
Object entry = symbolTable.get(symbol);
if (entry == null)
{
symbolTable.put(symbol, sig);
} else if (entry instanceof DigitalSignal)
{
List<Object> manySigs = new ArrayList<Object>();
manySigs.add(entry);
manySigs.add(sig);
symbolTable.put(symbol, manySigs);
} else if (entry instanceof List)
{
((List)entry).add(sig);
}
}
private void parseToEnd()
throws IOException
{
for(;;)
{
String keyword = getNextKeyword();
if (keyword == null || keyword.equals("$end")) break;
}
}
private String lastLine = null;
private int linePos;
private int lineLen;
private String getNextKeyword()
throws IOException
{
String keyword = null;
for(;;)
{
if (lastLine == null)
{
lastLine = getLineFromSimulator();
if (lastLine == null) break;
lineLen = lastLine.length();
linePos = 0;
}
if (linePos < lineLen)
{
char ch = lastLine.charAt(linePos);
if (ch == ' ' || ch == '\t')
{
linePos++;
} else
{
int startOfKeyword = linePos;
for(linePos++; linePos < lineLen; linePos++)
{
if (lastLine.charAt(linePos) == ' ') break;
}
keyword = lastLine.substring(startOfKeyword, linePos);
}
}
if (linePos >= lineLen) lastLine = null;
if (keyword != null) break;
}
return keyword;
}
}