/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ALS.java
* Asynchronous Logic Simulator main module
* Original C Code written by Brent Serbin and Peter J. Gallant
* Translated to Java by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2005 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.simulation.als;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.io.FileType;
import com.sun.electric.tool.simulation.DigitalAnalysis;
import com.sun.electric.tool.simulation.DigitalSignal;
import com.sun.electric.tool.simulation.Engine;
import com.sun.electric.tool.simulation.Signal;
import com.sun.electric.tool.simulation.Simulation;
import com.sun.electric.tool.simulation.Stimuli;
import com.sun.electric.tool.user.dialogs.OpenFile;
import com.sun.electric.tool.user.waveform.Panel;
import com.sun.electric.tool.user.waveform.WaveSignal;
import com.sun.electric.tool.user.waveform.WaveformWindow;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* Class to control the ALS Simulator.
*/
public class ALS extends Engine
{
/** initial size of simulation window */ private static final double DEFTIMERANGE = 0.0000002;
/** the simulation engine */ Sim theSim;
/** the circuit flattener */ Flat theFlat;
/** the waveform window showing this simulator */ WaveformWindow ww;
/** the stimuli set currently being displayed */ DigitalAnalysis an;
/** current time in the simulator */ double timeAbs;
/** saved list of stimuli when refreshing */ List<String> stimuliList;
List<Model> modelList;
List<Model> primList = new ArrayList<Model>();
IO ioPtr2;
Connect cellRoot = null;
ALSExport exPtr2;
List<Node> nodeList = new ArrayList<Node>();
Node driveNode;
Link linkFront = null;
Link linkBack = null;
Link setRoot = null;
List ioPtr1;
char [] instBuf = null;
int [] instPtr = null;
private int iPtr;
private String delay;
private Model modPtr2;
private String [] netlistStrings;
private int netlistStringPoint;
private int iBufSize;
private int iPtrSize;
private double deltaDef;
private double linearDef;
private double expDef;
private double randomDef;
private double absDef;
// /**
// * DelayTypes is a typesafe enum class that describes types of delay.
// */
// private static class DelayTypes
// {
// private DelayTypes() {}
//
// /**
// * Returns a printable version of this DelayTypes.
// * @return a printable version of this DelayTypes.
// */
// public String toString() { return ""; }
//
// /** Describes a minimum delay. */ public static final DelayTypes DELAY_MIN = new DelayTypes();
// /** Describes a typical delay. */ public static final DelayTypes DELAY_TYP = new DelayTypes();
// /** Describes a maximum delay. */ public static final DelayTypes DELAY_MAX = new DelayTypes();
// }
static class Model
{
String name;
char type;
Object ptr; /* may be Connect, Row, or Func */
List<ALSExport> exList;
List<IO> setList;
List<Load> loadList;
char fanOut;
int priority;
String level; /* hierarchical level */
Model(String name, char type)
{
this.name = name;
this.type = type;
ptr = null;
exList = new ArrayList<ALSExport>();
setList = new ArrayList<IO>();
loadList = new ArrayList<Load>();
fanOut = 0;
priority = 1;
}
};
static class Row
{
List<Object> inList;
List<Object> outList;
double delta;
double linear;
double exp;
double random;
double abs; /* BA delay - SDF absolute port delay */
Row next;
String delay; /* delay transition name (01, 10, etc) */
};
static class IO
{
Object nodePtr;
char operatr;
Object operand;
int strength;
};
static class Connect
{
String instName;
String modelName;
List<ALSExport> exList;
Connect parent;
Connect child;
Connect next;
};
static class ALSExport
{
Object nodeName;
Node nodePtr;
};
static class Load
{
Object ptr;
double load;
};
static class Node
{
Connect cellPtr;
DigitalSignal sig;
private int num;
int sumState;
int sumStrength;
Object newState;
int newStrength;
boolean traceNode;
List<Stat> statList;
List<Load> pinList;
double load;
int visit;
int arrive;
int depart;
double tLast;
private static int nSeq = 1;
Node()
{
num = nSeq++;
}
int getIndex() { return num; }
};
static class Stat
{
Model primPtr;
Node nodePtr;
int newState;
int newStrength;
char schedOp;
Object schedState;
int schedStrength;
};
static class Link
{
Link left;
Link right;
Link up;
Link down;
Object ptr;
char type;
char operatr;
Object state;
int strength;
int priority;
double time;
Model primHead;
};
static class Trak
{
int state;
double time;
};
static class Func
{
UserProc procPtr;
List<ALSExport> inList;
double delta;
double linear;
double exp;
double abs; /* absolute delay for back annotation */
double random;
Object userPtr;
};
static class UserProc
{
protected ALS als;
private static HashMap<String,UserProc> funcMap = new HashMap<String,UserProc>();
void nameMe(ALS als, String name)
{
this.als = als;
funcMap.put(name.toUpperCase(), this);
}
void simulate(Model primHead) {}
/**
* Method to return the address of the function specified by
* the calling argument character string. Each time a routine is added to the
* user library of event driven "C" functions an entry must be made into this
* procedure to include it in the known list of user routines. It is highly
* recommended that all user defined procedures be named with capital letters.
* This is done for two reasons: 1) the text in the netlist is converted to
* upper case by the parser and this means caps must be used in the string
* compare statements below, and 2) the user defined function routines will
* be easily identifiable in source code listings. Returns zero on error.
*
* Calling Arguments:
* s1 = pointer to character string containing the name of the user
* defined function
*/
static UserProc getFunctionAddress(String s1)
{
UserProc ret = funcMap.get(s1);
if (ret == null)
System.out.println("ERROR: Unable to find user function " + s1 + " in library");
return ret;
}
/**
* Method to insert a node updating task into the
* time scheduling link list. The user must specify the node address, signal
* state, signal strength, and update time in the calling arguments. If the
* user updates the value of a node manually without calling this procedure,
* the event driving algorithm will not be able to detect this change. This means
* that the effects of the node update will not be propagated throughout the
* simulation circuit automatically. By scheduling the event through the master
* link list, this problem can be avoided. Returns true on error.
*
* Calling Arguments:
* nodeHead = pointer to the node data structure to be updated
* operatr = char indicating operation to be performed on node
* state = integer value representing the state of the node
* strength = integer value representing the logic stregth of the signal
* time = double value representing the time the change is to take place
*/
protected void scheduleNodeUpdate(Model primHead, ALSExport exHead, int operatr,
Object state, int strength, double time)
{
Stat statHead = (Stat)exHead.nodeName;
if (statHead.schedOp == operatr && statHead.schedState == state &&
statHead.schedStrength == strength)
{
return;
}
if (als.getSim().tracing)
{
String s2 = als.computeNodeName(statHead.nodePtr);
System.out.println(" Schedule(F) gate " + statHead.primPtr.name + statHead.primPtr.level +
", net " + s2 + " at " + TextUtils.convertToEngineeringNotation(time));
}
Link linkPtr2 = new Link();
linkPtr2.type = 'G';
linkPtr2.ptr = statHead;
linkPtr2.operatr = statHead.schedOp = (char)operatr;
linkPtr2.state = statHead.schedState = state;
linkPtr2.strength = statHead.schedStrength = strength;
linkPtr2.priority = 1;
linkPtr2.time = time;
linkPtr2.primHead = primHead;
als.getSim().insertLinkList(linkPtr2);
}
/**
* Method to examine all the elements feeding into a node that is
* connected to the current bidirectional element and insures that there are no
* bidirectional "loops" found in the network paths. If a loop is found the
* effects of the element are ignored from the node summing calculation.
*
* Calling Arguments:
* primHead = pointer to current bidirectional element
* side[] = pointers to nodes on each side of the bidir element
* outStrength = output strength
*/
private Node targetNode;
private int biDirClock = 0;
protected void calculateBidirOutputs(Model primHead, ALSExport [] side, int outStrength)
{
for(int i=0; i<2; i++)
{
ALSExport thisSide = side[i];
ALSExport otherSide = side[(i+1)%2];
Node sumNode = thisSide.nodePtr;
targetNode = otherSide.nodePtr;
if (targetNode == als.driveNode) continue;
int state = ((Integer)sumNode.newState).intValue();
int strength = sumNode.newStrength;
biDirClock++;
for(Stat statHead : sumNode.statList)
{
if (statHead.primPtr == primHead) continue;
sumNode.visit = biDirClock;
int thisStrength = statHead.newStrength;
int thisState = statHead.newState;
if (thisStrength > strength)
{
state = thisState;
strength = thisStrength;
continue;
}
if (thisStrength == strength)
{
if (thisState != state) state = Stimuli.LOGIC_X;
}
}
// make strength no more than maximum output strength
if (strength > outStrength) strength = outStrength;
Func funcHead = (Func)primHead.ptr;
double time = als.timeAbs + (funcHead.delta * targetNode.load);
scheduleNodeUpdate(primHead, otherSide, '=', new Integer(state), strength, time);
}
}
}
ALS()
{
theSim = new Sim(this);
theFlat = new Flat(this);
}
Sim getSim() { return theSim; }
/**
* Method to simulate the a Cell, given its context and the Cell with the real netlist.
* @param netlistCell the Cell with the real ALS netlist.
* @param cell the original Cell being simulated.
*/
public static void simulateNetlist(Cell netlistCell, Cell cell)
{
ALS theALS = new ALS();
theALS.doSimulation(netlistCell, cell, null, null);
}
/**
* Method to restart a simulation and reload the circuit.
* @param netlistCell the cell with the netlist.
* @param cell the cell being simulated.
* @param prevALS the simulation that is being reloaded.
*/
public static void restartSimulation(Cell netlistCell, Cell cell, ALS prevALS)
{
WaveformWindow ww = prevALS.ww;
List<String> stimuliList = prevALS.stimuliList;
ALS theALS = new ALS();
theALS.doSimulation(netlistCell, cell, ww, stimuliList);
}
/**
* Method to reload the circuit data.
*/
public void refresh()
{
// save existing stimuli in this simulator object
stimuliList = getStimuliToSave();
// restart everything
Simulation.startSimulation(Simulation.ALS_ENGINE, false, an.getStimuli().getCell(), this);
}
/**
* Method to update the simulation (because some stimuli have changed).
*/
public void update()
{
theSim.initializeSimulator(true);
}
/**
* Method to set the currently-selected signal high at the current time.
*/
public void setSignalHigh()
{
makeThemThus(Stimuli.LOGIC_HIGH);
}
/**
* Method to set the currently-selected signal low at the current time.
*/
public void setSignalLow()
{
makeThemThus(Stimuli.LOGIC_LOW);
}
/**
* Method to set the currently-selected signal to have a clock with a given period.
*/
public void setClock(double period)
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal before setting a Clock on it",
"No Signals Selected");
return;
}
for(Signal sig : signals)
{
String sigName = sig.getFullName();
Node nodeHead = findNode(sigName);
if (nodeHead == null)
{
System.out.println("ERROR: Unable to find node " + sigName);
continue;
}
double time = ww.getMainXPositionCursor();
Link vectPtr2 = new Link();
vectPtr2.type = 'N';
vectPtr2.ptr = nodeHead;
vectPtr2.state = new Integer(Stimuli.LOGIC_HIGH);
vectPtr2.strength = Stimuli.VDD_STRENGTH;
vectPtr2.priority = 1;
vectPtr2.time = time;
vectPtr2.right = null;
Link vectPtr1 = new Link();
vectPtr1.type = 'N';
vectPtr1.ptr = nodeHead;
vectPtr1.state = new Integer(Stimuli.LOGIC_LOW);
vectPtr1.strength = Stimuli.VDD_STRENGTH;
vectPtr1.priority = 1;
vectPtr1.time = period / 2.0;
vectPtr1.right = vectPtr2;
Row clokHead = new Row();
clokHead.inList = new ArrayList<Object>();
clokHead.inList.add(vectPtr1);
clokHead.inList.add(vectPtr2);
clokHead.outList = new ArrayList<Object>();
clokHead.delta = period;
clokHead.linear = 0;
clokHead.exp = 0;
clokHead.abs = 0;
clokHead.random = 0;
clokHead.next = null;
clokHead.delay = null;
Link setHead = new Link();
setHead.type = 'C';
setHead.ptr = clokHead;
setHead.state = new Integer(0);
setHead.priority = 1;
setHead.time = time;
setHead.right = null;
insertSetList(setHead);
}
theSim.initializeSimulator(true);
}
/**
* Method to set the currently-selected signal undefined at the current time.
*/
public void setSignalX()
{
makeThemThus(Stimuli.LOGIC_X);
}
/**
* Method to show information about the currently-selected signal.
*/
public void showSignalInfo()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal before displaying it",
"No Signals Selected");
return;
}
for(Signal sig : signals)
{
Node nodeHead = findNode(sig.getFullName());
if (nodeHead == null)
{
System.out.println("ERROR: Unable to find node " + sig.getFullName());
continue;
}
String s1 = Stimuli.describeLevel(((Integer)nodeHead.newState).intValue());
System.out.println("Node " + sig.getFullName() + ": State = " + s1 +
", Strength = " + Stimuli.describeStrength(nodeHead.newStrength));
for(Stat statHead : nodeHead.statList)
{
s1 = Stimuli.describeLevel(statHead.newState);
System.out.println("Primitive " + statHead.primPtr.name + ": State = " + s1 +
", Strength = " + Stimuli.describeStrength(statHead.newStrength));
}
}
}
/**
* Method to remove all stimuli from the currently-selected signals.
*/
public void removeStimuliFromSignal()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal on which to clear stimuli",
"No Signals Selected");
return;
}
for(Signal sig : signals)
{
sig.clearControlPoints();
Link lastSet = null;
Link nextSet = null;
for(Link thisSet = setRoot; thisSet != null; thisSet = nextSet)
{
nextSet = thisSet.right;
boolean delete = false;
if (thisSet.ptr instanceof Node)
{
Node node = (Node)thisSet.ptr;
if (node.sig == sig) delete = true;
} else if (thisSet.ptr instanceof Row)
{
Row clokHead = (Row)thisSet.ptr;
Iterator<Object> cIt = clokHead.inList.iterator();
if (cIt.hasNext())
{
Link vectHead = (Link)cIt.next();
Node node = (Node)vectHead.ptr;
if (node.sig == sig) delete = true;
}
}
if (delete)
{
if (lastSet == null) setRoot = nextSet; else
lastSet.right = nextSet;
} else
{
lastSet = thisSet;
}
}
}
if (Simulation.isBuiltInResimulateEach())
{
theSim.initializeSimulator(true);
}
}
/**
* Method to remove the selected stimuli.
* @return true if stimuli were deleted.
*/
public boolean removeSelectedStimuli()
{
boolean found = false;
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel wp = it.next();
for(WaveSignal ws : wp.getSignals())
{
if (!ws.isHighlighted()) continue;
double [] selectedCPs = ws.getSelectedControlPoints();
if (selectedCPs == null) continue;
for(int i=0; i<selectedCPs.length; i++)
{
Signal sig = ws.getSignal();
Link lastSet = null;
Link nextSet = null;
for(Link thisSet = setRoot; thisSet != null; thisSet = nextSet)
{
nextSet = thisSet.right;
boolean delete = false;
if (thisSet.time == selectedCPs[i])
{
if (thisSet.ptr instanceof Node)
{
Node node = (Node)thisSet.ptr;
if (node.sig == sig) delete = true;
} else if (thisSet.ptr instanceof Row)
{
Row clokHead = (Row)thisSet.ptr;
Iterator<Object> cIt = clokHead.inList.iterator();
if (cIt.hasNext())
{
Link vectHead = (Link)cIt.next();
Node node = (Node)vectHead.ptr;
if (node.sig == sig) delete = true;
}
}
}
if (delete)
{
sig.removeControlPoint(thisSet.time);
if (lastSet == null) setRoot = nextSet; else
lastSet.right= nextSet;
found = true;
break;
}
lastSet = thisSet;
}
}
}
}
if (!found)
{
System.out.println("There are no selected control points to remove");
return false;
}
if (Simulation.isBuiltInResimulateEach())
{
theSim.initializeSimulator(true);
}
return true;
}
/**
* Method to remove all stimuli from the simulation.
*/
public void removeAllStimuli()
{
clearAllVectors(false);
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel wp = it.next();
for(WaveSignal ws : wp.getSignals())
{
Signal sig = ws.getSignal();
sig.clearControlPoints();
}
}
if (Simulation.isBuiltInResimulateEach())
{
theSim.initializeSimulator(true);
}
}
/**
* Method to save the current stimuli information to disk.
*/
public void saveStimuli()
{
String stimuliFileName = OpenFile.chooseOutputFile(FileType.ALSVECTOR, "ALS Vector file", an.getStimuli().getCell().getName() + ".vec");
if (stimuliFileName == null) return;
try
{
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(stimuliFileName)));
List<String> stimuliList = getStimuliToSave();
for(String str : stimuliList)
printWriter.println(str);
printWriter.close();
} catch (IOException e)
{
System.out.println("Error writing results");
return;
}
System.out.println("Wrote " + stimuliFileName);
}
/**
* Method to restore the current stimuli information from disk.
*/
public void restoreStimuli()
{
String stimuliFileName = OpenFile.chooseInputFile(FileType.ALSVECTOR, "ALS Vector file");
if (stimuliFileName == null) return;
List<String> stimuliList = new ArrayList<String>();
URL url = TextUtils.makeURLToFile(stimuliFileName);
try
{
URLConnection urlCon = url.openConnection();
InputStreamReader is = new InputStreamReader(urlCon.getInputStream());
LineNumberReader lineReader = new LineNumberReader(is);
for(;;)
{
String s1 = lineReader.readLine();
if (s1 == null) break;
stimuliList.add(s1);
}
lineReader.close();
} catch (IOException e)
{
System.out.println("Error reading " + stimuliFileName);
return;
}
processStimuliList(stimuliList);
}
/********************************** INTERFACE SUPPORT **********************************/
private void init()
{
// create the user-defined functions
new UserCom.PMOSTran(this);
new UserCom.PMOSTranWeak(this);
new UserCom.NMOSTran(this);
new UserCom.NMOSTranWeak(this);
new UserCom.JKFlop(this);
new UserCom.DFFlop(this);
new UserCom.BusToState(this);
new UserCom.StateToBus(this);
// not used:
// new UserCom.Counter();
// new UserCom.DelayCalc();
// new UserCom.FIFO();
// new UserCom.RXData();
// new UserCom.AFRegisters();
// new UserCom.ControlLogic();
// new UserCom.Mod2Adder();
// new UserCom.AboveAdder();
// new UserCom.Bus12ToState();
// allocate memory
if (instBuf == null)
instBuf = new char[iBufSize=100];
if (instPtr == null)
instPtr = new int[iPtrSize=100];
}
private void doSimulation(Cell netlistCell, Cell cell, WaveformWindow oldWW, List<String> stimuliList)
{
// initialize memory
init();
// read netlist
eraseModel();
if (readNetDesc(netlistCell)) return;
if (theFlat.flattenNetwork(cell)) return;
// initialize display
an = getCircuit(cell);
ww = oldWW;
Simulation.showSimulationData(an.getStimuli(), ww);
// make a waveform window
if (ww == null)
ww = an.getStimuli().getWaveformWindow();
if (stimuliList != null) processStimuliList(stimuliList);
// run simulation
theSim.initializeSimulator(true);
}
private void makeThemThus(int state)
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal on which to set stimuli",
"No Signals Selected");
return;
}
for(Signal sig : signals)
{
String sigName = sig.getFullName();
Node nodeHead = findNode(sigName);
if (nodeHead == null)
{
System.out.println("ERROR: Unable to find node " + sigName);
return;
}
int strength = Stimuli.NODE_STRENGTH;
double time = ww.getMainXPositionCursor();
Link setHead = new Link();
setHead.type = 'N';
setHead.ptr = nodeHead;
setHead.state = new Integer(state);
setHead.strength = strength;
setHead.priority = 2;
setHead.time = time;
setHead.right = null;
sig.addControlPoint(time);
insertSetList(setHead);
// System.out.println("Node '" + sigName + "' scheduled, state = " + state +
// ", strength = " + Stimuli.describeStrength(strength) + ", time = " + time);
}
if (Simulation.isBuiltInResimulateEach())
{
double endTime = theSim.initializeSimulator(true);
if (Simulation.isBuiltInAutoAdvance()) ww.setMainXPositionCursor(endTime);
}
}
/**
* Method to insert a data element into a linklist that is sorted
* by time and then priority. This link list is used to schedule events
* for the simulation.
*
* Calling Arguments:
* linkHead = pointer to the data element that is going to be inserted
*/
void insertSetList(Link linkHead)
{
// linkPtr1Is: 0: ALS.setRoot 1: linkptr1.right
int linkPtr1Is = 0;
Link linkPtr1 = null;
for(;;)
{
Link linkPtr2 = setRoot;
if (linkPtr1Is == 1) linkPtr2 = linkPtr1.right;
if (linkPtr2 == null)
{
if (linkPtr1Is == 0) setRoot = linkHead; else
linkPtr1.right = linkHead;
break;
}
if (linkPtr2.time > linkHead.time || (linkPtr2.time == linkHead.time &&
linkPtr2.priority > linkHead.priority))
{
linkHead.right = linkPtr2;
if (linkPtr1Is == 0) setRoot = linkHead; else
linkPtr1.right = linkHead;
break;
}
linkPtr1 = linkPtr2;
linkPtr1Is = 1;
}
}
private void eraseModel()
{
// reset miscellaneous simulation variables
linkFront = null;
linkBack = null;
// delete all test vectors
clearAllVectors(true);
// delete all cells in flattened network
cellRoot = null;
// delete all nodes in flattened network
nodeList = new ArrayList<Node>();
// delete all primitives in flattened network
primList = new ArrayList<Model>();
// delete each model/gate/function in hierarchical description
modelList = new ArrayList<Model>();
}
/**
* Method to clear all test vectors (even the power and ground vectors if "pwrGnd"
* is true).
*/
private void clearAllVectors(boolean pwrGnd)
{
Link lastSet = null;
Link nextSet = null;
for(Link thisSet = setRoot; thisSet != null; thisSet = nextSet)
{
nextSet = thisSet.right;
if (pwrGnd || thisSet.strength != Stimuli.VDD_STRENGTH)
{
if (lastSet == null) setRoot = nextSet; else
lastSet.right= nextSet;
} else
{
lastSet = thisSet;
}
}
}
private DigitalAnalysis getCircuit(Cell cell)
{
// convert the stimuli
Stimuli sd = new Stimuli();
sd.setDataType(FileType.ALS);
sd.setEngine(this);
DigitalAnalysis an = new DigitalAnalysis(sd, true);
sd.setSeparatorChar('.');
sd.setCell(cell);
String topLevelName = cell.getName().toUpperCase();
for(Connect cr = cellRoot; cr != null; cr = cr.next)
{
if (cr.modelName.equals(topLevelName))
{
addExports(cr, an, null);
break;
}
}
return an;
}
private void addExports(Connect cr, DigitalAnalysis an, String context)
{
// determine type of model
for(Model modPtr1 : modelList)
{
if (modPtr1.name.equals(cr.modelName))
{
if (modPtr1.type != 'M') return;
break;
}
}
for(ALSExport e : cr.exList)
{
if (e.nodePtr.sig != null) continue;
DigitalSignal sig = new DigitalSignal(an);
e.nodePtr.sig = sig;
sig.setSignalName((String)e.nodeName, context);
sig.buildTime(2);
sig.buildState(2);
sig.setTime(0, 0);
sig.setTime(1, DEFTIMERANGE);
sig.setState(0, 0);
sig.setState(1, 0);
}
String subContext = context;
if (subContext == null) subContext = ""; else subContext += ".";
for(Connect child = cr.child; child != null; child = child.next)
{
addExports(child, an, subContext + child.instName);
}
}
private List<String> getStimuliToSave()
{
List<String> stimuliList = new ArrayList<String>();
for (Link setHead = setRoot; setHead != null; setHead = setHead.right)
{
switch (setHead.type)
{
case 'C':
Row clokHead = (Row)setHead.ptr;
List<Object> vectList = clokHead.inList;
boolean first = true;
for(Object obj : vectList)
{
Link vectHead = (Link)obj;
if (first)
{
String s1 = computeNodeName((Node)vectHead.ptr);
stimuliList.add("CLOCK " + s1 + " D=" + clokHead.delta + " L=" + clokHead.linear +
" E=" + clokHead.exp + " STRENGTH=" + Stimuli.strengthToIndex(vectHead.strength) + " TIME=" + setHead.time + " CYCLES=" + setHead.state);
first = false;
}
String s2 = Stimuli.describeLevelBriefly(((Integer)vectHead.state).intValue());
stimuliList.add(" " + s2 + " " + vectHead.time);
}
break;
case 'N':
String s1 = computeNodeName((Node)setHead.ptr);
String s2 = Stimuli.describeLevelBriefly(((Integer)setHead.state).intValue());
stimuliList.add("SET " + s1 + "=" + s2 + "@" + Stimuli.strengthToIndex(setHead.strength) + " TIME=" + setHead.time);
}
}
return stimuliList;
}
private void processStimuliList(List<String> stimuliList)
{
// clear all vectors
while (setRoot != null)
{
setRoot = setRoot.right;
}
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel wp = it.next();
for(WaveSignal ws : wp.getSignals())
{
Signal sig = ws.getSignal();
sig.clearControlPoints();
}
}
boolean flag = true;
String [] parts = null;
Iterator<String> sIt = stimuliList.iterator();
for(;;)
{
String s1 = null;
if (flag)
{
if (!sIt.hasNext())
{
theSim.initializeSimulator(true);
break;
}
s1 = sIt.next();
s1 = s1.toUpperCase();
parts = fragmentCommand(s1);
}
flag = true;
if (parts == null || parts.length < 1) continue;
String command = parts[0];
if (command.equals("CLOCK"))
{
if (parts.length < 14)
{
System.out.println("Error: CLOCK stimuli line has only " + parts.length + " fields: " + s1);
continue;
}
String nodeName = parts[1];
Node nodeHead = findNode(nodeName);
if (nodeHead == null)
{
System.out.println("ERROR: Unable to find node " + nodeName);
continue;
}
int strength = Stimuli.indexToStrength(TextUtils.atoi(parts[9]));
Link setHead = new Link();
setHead.type = 'C';
Row clokHead = new Row();
setHead.ptr = clokHead;
setHead.state = new Integer(TextUtils.atoi(parts[13]));
setHead.priority = 1;
setHead.time = TextUtils.atof(parts[11]);
setHead.right = null;
insertSetList(setHead);
if (nodeHead.sig != null)
nodeHead.sig.addControlPoint(setHead.time);
clokHead.delta = TextUtils.atof(parts[3]);
clokHead.linear = TextUtils.atof(parts[5]);
clokHead.exp = TextUtils.atof(parts[7]);
clokHead.abs = 0;
clokHead.random = 0;
clokHead.next = null;
clokHead.delay = null;
clokHead.inList = new ArrayList<Object>();
for(;;)
{
if (!sIt.hasNext())
{
theSim.initializeSimulator(false);
return;
}
s1 = sIt.next();
parts = fragmentCommand(s1.toUpperCase());
String com = parts[0];
if (com.equals("CLOCK") || com.equals("SET"))
{
flag = false;
break;
}
Link vectPtr2 = new Link();
vectPtr2.type = 'N';
vectPtr2.ptr = nodeHead;
vectPtr2.state = new Integer(Stimuli.parseLevel(com));
vectPtr2.strength = strength;
vectPtr2.priority = 1;
vectPtr2.time = TextUtils.atof(parts[1]);
vectPtr2.right = null;
clokHead.inList.add(vectPtr2);
}
}
if (command.equals("SET"))
{
if (parts.length < 6)
{
System.out.println("Error: SET stimuli line has only " + parts.length + " fields: " + s1);
continue;
}
String nodeName = parts[1];
Node nodeHead = findNode(nodeName);
if (nodeHead == null)
{
System.out.println("ERROR: Unable to find node " + nodeName);
continue;
}
Link setHead = new Link();
setHead.type = 'N';
setHead.ptr = nodeHead;
setHead.state = new Integer(Stimuli.parseLevel(parts[2]));
setHead.strength = Stimuli.indexToStrength(TextUtils.atoi(parts[3]));
setHead.priority = 2;
setHead.time = TextUtils.atof(parts[5]);
setHead.right = null;
insertSetList(setHead);
if (nodeHead.sig != null)
nodeHead.sig.addControlPoint(setHead.time);
}
}
}
/**
* Method to processe the string specified by the calling argument
* and fragments it into a series of smaller character strings, each of which
* is terminated by a null character. Returns true on error.
*
* Calling Arguments:
* line = pointer to the character string to be fragmented
*/
private String [] fragmentCommand(String line)
{
List<String> fragments = new ArrayList<String>();
line = line.trim();
for(int i=0; i<line.length(); i++)
{
int spacePos = line.indexOf(' ', i);
if (spacePos < 0) spacePos = line.length();
int equalPos = line.indexOf('=', i);
if (equalPos < 0) equalPos = line.length();
int atPos = line.indexOf('@', i);
if (atPos < 0) atPos = line.length();
int pos = Math.min(Math.min(spacePos, equalPos), atPos);
if (pos < 0)
{
fragments.add(line.substring(i));
break;
}
fragments.add(line.substring(i, pos));
i = pos;
}
String [] parts = new String[fragments.size()];
for(int i=0; i<fragments.size(); i++) parts[i] = fragments.get(i);
return parts;
}
/**
* Method to return a pointer to a structure in the cross reference
* table. The calling argument string contains information detailing the path
* name to the desired level in the cross reference table.
*
* Calling Argument:
* sp = pointer to char string containing path name to level in xref table
*/
Connect findLevel(String sp)
{
Connect cellPtr = cellRoot;
if (sp.startsWith(".")) sp = sp.substring(1);
while (sp.length() > 0)
{
String part = sp;
sp = "";
int dotPos = part.indexOf('.');
if (dotPos >= 0)
{
sp = part.substring(dotPos+1);
part = part.substring(0, dotPos);
}
for( ; ; cellPtr = cellPtr.next)
{
if (cellPtr == null) return null;
if (part.equals(cellPtr.instName))
{
if (sp.length() > 0)
cellPtr = cellPtr.child;
break;
}
}
}
return cellPtr;
}
/**
* Method to compose a character string which indicates the node name
* for the nodePtr specified in the calling argument.
*
* Calling Arguments:
* nodeHead = pointer to desired node in database
* sp = pointer to char string where complete name is to be saved
*/
String computeNodeName(Node nodeHead)
{
Connect cellHead = nodeHead.cellPtr;
String sp = computePathName(cellHead);
for(ALSExport exHead : cellHead.exList)
{
if (nodeHead == exHead.nodePtr)
{
sp += "." + exHead.nodeName;
return sp;
}
}
return "";
}
/**
* Method to compose a character string which indicates the path name
* to the level of hierarchy specified in the calling argument.
*
* Calling Arguments:
* cellHead = pointer to desired level of hierarchy
* sp = pointer to char string where path name is to be saved
*/
String computePathName(Connect cellHead)
{
StringBuffer infstr = new StringBuffer();
for ( ; cellHead != null; cellHead = cellHead.parent)
infstr.append("." + cellHead.instName);
return infstr.toString();
}
/**
* Method to return a pointer to the calling routine which indicates
* the address of the node entry in the database. The calling argument string
* contains information detailing the path name to the desired node.
*
* Calling Argument:
* sp = pointer to char string containing path name to node
*/
private Node findNode(String sp)
{
if (sp.startsWith("$N"))
{
int i = TextUtils.atoi(sp.substring(2));
for(Node nodeHead : nodeList)
{
if (nodeHead.num == i) return nodeHead;
}
return null;
}
int dotPos = sp.lastIndexOf('.');
String s2 = sp;
Connect cellPtr = findLevel(an.getStimuli().getCell().getName().toUpperCase());
if (dotPos >= 0)
{
s2 = sp.substring(dotPos+1);
cellPtr = findLevel(sp.substring(0, dotPos));
}
if (cellPtr == null) cellPtr = cellRoot;
for(ALSExport exHead : cellPtr.exList)
{
if (exHead.nodeName.equals(s2)) return exHead.nodePtr;
}
return null;
}
/********************************** PARSING NETLISTS **********************************/
/**
* Method to read a netlist description of the logic network
* to be analysed in other procedures. Returns true on error.
*/
private boolean readNetDesc(Cell cell)
{
netlistStrings = cell.getTextViewContents();
if (netlistStrings == null)
{
System.out.println("No netlist information found in " + cell);
return true;
}
netlistStringPoint = 0;
System.out.println("Simulating netlist in " + cell);
instPtr[0] = -1;
iPtr = 0;
for(;;)
{
String s1 = getAString();
if (s1 == null) break;
if (s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL"))
{
if (parseStructHeader(s1.charAt(0))) return true;
continue;
}
System.out.println("ERROR: String '" + s1 + "' invalid (expecting gate, function, or model)");
return true;
}
return false;
}
/**
* Method to parse the input text used to describe the header for
* a top level structure (gate, function, model). The structure name and
* argument list (exported node names) are entered into the database. Returns
* nonzero on error.
* @param flag char representing the type of structure to be parsed
*/
private boolean parseStructHeader(char flag)
{
String s1 = getAName();
if (s1 == null)
{
System.out.println("Structure declaration: EOF unexpectedly found");
return true;
}
for(Model modPtr1 : modelList)
{
if (modPtr1.name.equals(s1))
{
System.out.println("ERROR: Structure " + s1 + " already defined");
return true;
}
}
modPtr2 = new Model(s1, flag);
modPtr2.fanOut = 1;
modelList.add(modPtr2);
s1 = getAString();
if (s1 == null)
{
System.out.println("Structure declaration: EOF unexpectedly found");
return true;
}
if (!s1.startsWith("("))
{
System.out.println("Structure declaration: Expecting to find '(' in place of string '" + s1 + "'");
return true;
}
for(;;)
{
s1 = getAName();
if (s1 == null)
{
System.out.println("Structure declaration: EOF unexpectedly found");
return true;
}
if (s1.startsWith(")")) break;
for(ALSExport exPtr1 : modPtr2.exList)
{
if (exPtr1.nodeName.equals(s1))
{
System.out.println("Node " + s1 + " specified more than once in argument list");
return true;
}
}
exPtr2 = new ALSExport();
exPtr2.nodeName = s1;
exPtr2.nodePtr = null;
modPtr2.exList.add(exPtr2);
}
switch (flag)
{
case 'G':
if (parseGate()) return true;
return false;
case 'F':
if (parseFunction()) return true;
return false;
case 'M':
if (parseModel()) return true;
return false;
}
System.out.println("Error in parser: invalid structure type");
return true;
}
/**
* Method to parse the text used to describe a gate entity.
* The user specifies truth table entries, loading factors, and timing parameters
* in this region of the netlist. Returns true on error.
*/
private boolean parseGate()
{
// init delay transition name
delay = "XX";
deltaDef = linearDef = expDef = randomDef = absDef = 0;
Object last = modPtr2;
Row rowPtr2 = null;
for(;;)
{
String s1 = getAString();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL"))
{
--iPtr;
break;
}
if (s1.equals("I"))
{
rowPtr2 = new Row();
rowPtr2.inList = new ArrayList<Object>();
rowPtr2.outList = new ArrayList<Object>();
rowPtr2.delta = deltaDef;
rowPtr2.linear = linearDef;
rowPtr2.exp = expDef;
rowPtr2.random = randomDef;
rowPtr2.abs = absDef;
rowPtr2.delay = delay;
delay = "XX";
rowPtr2.next = null;
if (last instanceof Row) ((Row)last).next = rowPtr2; else
((Model)last).ptr = rowPtr2;
last = rowPtr2;
ioPtr1 = rowPtr2.inList;
if (parseNode()) return true;
continue;
}
if (s1.equals("O"))
{
ioPtr1 = rowPtr2.outList;
if (parseNode()) return true;
continue;
}
if (s1.equals("T"))
{
if (parseTiming()) return true;
continue;
}
if (s1.equals("D"))
{
if (parseDelay()) return true;
continue;
}
if (s1.equals("FANOUT"))
{
if (parseFanOut()) return true;
continue;
}
if (s1.equals("LOAD"))
{
if (parseLoad()) return true;
continue;
}
if (s1.equals("PRIORITY"))
{
Integer jj = getAnInt();
if (jj == null)
{
System.out.println("Priority declaration: EOF unexpectedly found");
return true;
}
modPtr2.priority = jj.intValue();
continue;
}
if (s1.equals("SET"))
{
ioPtr1 = modPtr2.setList;
if (parseNode()) return true;
continue;
}
System.out.println("ERROR: String '" + s1 + "' invalid gate syntax");
return true;
}
return false;
}
/**
* Method to create an entry in the database for one of the nodes
* that belong to a row entry or set state entry. Returns true on error.
*/
private boolean parseNode()
{
for(;;)
{
String s1 = getAName();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") ||
s1.equals("MODEL") || s1.equals("I") || s1.equals("O") ||
s1.equals("T") || s1.equals("FANOUT") || s1.equals("LOAD") ||
s1.equals("PRIORITY") || s1.equals("SET"))
{
--iPtr;
break;
}
ioPtr2 = new IO();
ioPtr2.nodePtr = s1;
ioPtr2.strength = Stimuli.GATE_STRENGTH;
ioPtr1.add(ioPtr2);
s1 = getAString();
if (s1 == null)
{
System.out.println("Node declaration: EOF unexpectedly found");
return true;
}
switch (s1.charAt(0))
{
case '=':
case '!':
case '>':
case '<':
case '+':
case '-':
case '*':
case '/':
case '%':
break;
default:
System.out.println("Gate declaration: Invalid Operator '" + s1 + "'");
return true;
}
ioPtr2.operatr = s1.charAt(0);
s1 = getAString();
if (s1 == null)
{
System.out.println("Node declaration: EOF unexpectedly found");
return true;
}
if (s1.equals("L") || s1.equals("X") || s1.equals("H"))
{
ioPtr2.operand = new Integer(Stimuli.parseLevel(s1));
} else
{
--iPtr;
if (s1.charAt(0) == '+' || s1.charAt(0) == '-' || TextUtils.isDigit(s1.charAt(0)))
{
Integer jj = getAnInt();
if (jj == null)
{
System.out.println("Node declaration: EOF unexpectedly found");
return true;
}
ioPtr2.operand = jj;
} else
{
s1 = getAName();
if (s1 == null)
{
System.out.println("Node declaration: EOF unexpectedly found");
return true;
}
ioPtr2.operand = s1;
ioPtr2.operatr += 128;
}
}
s1 = getAString();
if (s1 == null || !s1.startsWith("@"))
{
--iPtr;
continue;
}
Integer jj = getAnInt();
if (jj == null)
{
System.out.println("Node declaration: EOF unexpectedly found");
return true;
}
ioPtr2.strength = Stimuli.indexToStrength(jj.intValue());
}
return false;
}
/**
* Method to insert timing values into the appropriate places in
* the database. Returns true on error.
*/
private boolean parseTiming()
{
deltaDef = linearDef = expDef = randomDef = absDef = 0;
for(;;)
{
String s1 = getAString();
if (s1 == null)
{
System.out.println("Timing declaration: EOF unexpectedly found");
return true;
}
String s2 = getAString();
if (s2 == null)
{
System.out.println("Timing declaration: EOF unexpectedly found");
return true;
}
if (!s2.startsWith("="))
{
System.out.println("Timing declaration: Invalid Operator '" + s2 + "' (expecting '=')");
return true;
}
Double value = getADouble();
if (value == null)
{
System.out.println("Timing declaration: EOF unexpectedly found");
return true;
}
switch (s1.charAt(0))
{
case 'A':
absDef = value.doubleValue();
break;
case 'D':
deltaDef = value.doubleValue();
break;
case 'E':
expDef = value.doubleValue();
break;
case 'L':
linearDef = value.doubleValue();
break;
case 'R':
randomDef = value.doubleValue();
if (value.doubleValue() > 0.0) modPtr2.priority = 2;
break;
default:
System.out.println("Invalid timing mode '" + s1 + "'");
return true;
}
s1 = getAString();
if (s1 == null || !s1.startsWith("+"))
{
--iPtr;
break;
}
}
return false;
}
/**
* Method to set the delay transition type for the current input state.
*/
private boolean parseDelay()
{
String s1 = getAString();
if (s1 == null)
{
System.out.println("Timing declaration: EOF unexpectedly found");
return true;
}
if (!s1.equals("01") && !s1.equals("10") && !s1.equals("OZ") && !s1.equals("Z1") &&
!s1.equals("1Z") && !s1.equals("Z0") && !s1.equals("0X") && !s1.equals("X1") &&
!s1.equals("1X") && !s1.equals("X0") && !s1.equals("XZ") && !s1.equals("ZX"))
{
System.out.println("Invalid delay transition name '" + s1 + "'");
return true;
}
delay = s1;
return false;
}
/**
* Method to set a flag in the model data structure regarding
* if fanout calculations are to be performed for this models output.
* If fanout calculations are required the model should have a single output.
* Returns true on error.
*/
private boolean parseFanOut()
{
String s1 = getAString();
if (s1 == null)
{
System.out.println("Fanout declaration: EOF unexpectedly found");
return true;
}
if (!s1.startsWith("="))
{
System.out.println("Fanout declaration: Invalid Operator '" + s1 + "' (expecting '=')");
return true;
}
s1 = getAString();
if (s1 == null)
{
System.out.println("Fanout declaration: EOF unexpectedly found");
return true;
}
if (s1.equals("ON"))
{
modPtr2.fanOut = 1;
return false;
}
if (s1.equals("OFF"))
{
modPtr2.fanOut = 0;
return false;
}
System.out.println("Fanout declaration: Invalid option '" + s1 + "'");
return true;
}
/**
* Method to enter the capacitive load rating (on per unit basis)
* into the database for the specified node. Returns true on error.
*/
private boolean parseLoad()
{
for(;;)
{
String s1 = getAName();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL") ||
s1.equals("I") || s1.equals("O") || s1.equals("T") || s1.equals("FANOUT") ||
s1.equals("LOAD") || s1.equals("PRIORITY") || s1.equals("SET"))
{
--iPtr;
break;
}
String s2 = getAString();
if (s2 == null)
{
System.out.println("Load declaration: EOF unexpectedly found");
return true;
}
if (s2.charAt(0) != '=')
{
System.out.println("Load declaration: Invalid Operator '" + s2 + "' (expecting '=')");
return true;
}
Double load = getADouble();
if (load == null)
{
System.out.println("Load declaration: EOF unexpectedly found");
return true;
}
Load loadPtr2 = new Load();
loadPtr2.ptr = s1;
loadPtr2.load = load.doubleValue();
modPtr2.loadList.add(loadPtr2);
}
return false;
}
/**
* Method to parse the text used to describe a model entity.
* The user specifies the interconnection of lower level primitives (gates and
* functions) in this region of the netlist. Returns true on error.
*/
private boolean parseModel()
{
for(;;)
{
String s1 = getAName();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL"))
{
--iPtr;
break;
}
if (s1.charAt(0) == '}') continue;
if (s1.equals("SET"))
{
ioPtr1 = modPtr2.setList;
if (parseNode()) return true;
continue;
}
for(Object conptr1 = modPtr2.ptr; conptr1 != null; conptr1 = ((Connect)conptr1).next)
{
Connect cp1 = (Connect)conptr1;
if (cp1.instName.equals(s1))
{
System.out.println("ERROR: Instance name '" + s1 + "' defined more than once");
return true;
}
}
Connect conPtr2 = new Connect();
conPtr2.instName = s1;
conPtr2.modelName = null;
conPtr2.exList = new ArrayList<ALSExport>();
conPtr2.next = (Connect)modPtr2.ptr;
modPtr2.ptr = conPtr2;
s1 = getAName();
if (s1 == null)
{
System.out.println("Model declaration: EOF unexpectedly found");
return true;
}
conPtr2.modelName = s1;
s1 = getAString();
if (s1 == null)
{
System.out.println("Model declaration: EOF unexpectedly found");
return true;
}
if (s1.charAt(0) != '(')
{
System.out.println("Model declaration: Expecting to find '(' in place of string '" + s1 + "'");
return true;
}
for(;;)
{
s1 = getAName();
if (s1 == null)
{
System.out.println("Model declaration: EOF unexpectedly found");
return true;
}
if (s1.charAt(0) == ')') break;
exPtr2 = new ALSExport();
exPtr2.nodePtr = null;
exPtr2.nodeName = s1;
conPtr2.exList.add(exPtr2);
}
}
return false;
}
/**
* Method to parse the text used to describe a function entity.
* The user specifies input entries, loading factors, and timing parameters
* in this region of the netlist.
*/
private boolean parseFunction()
{
modPtr2.fanOut = 0;
Func funcHead = new Func();
modPtr2.ptr = funcHead;
funcHead.procPtr = null;
funcHead.inList = new ArrayList<ALSExport>();
funcHead.delta = 0;
funcHead.linear = 0;
funcHead.exp = 0;
funcHead.abs = 0;
funcHead.random = 0;
funcHead.userPtr = null;
for(;;)
{
String s1 = getAString();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL"))
{
--iPtr;
break;
}
if (s1.equals("I"))
{
parseFuncInput(funcHead);
continue;
}
if (s1.equals("O"))
{
if (parseFuncOutput()) return true;
continue;
}
if (s1.equals("T"))
{
if (parseTiming()) return true;
funcHead.delta = deltaDef;
funcHead.linear = linearDef;
funcHead.exp = expDef;
funcHead.abs = absDef;
funcHead.random = randomDef;
continue;
}
if (s1.equals("LOAD"))
{
if (parseLoad()) return true;
continue;
}
if (s1.equals("PRIORITY"))
{
Integer jj = getAnInt();
if (jj == null)
{
System.out.println("Priority declaration: EOF unexpectedly found");
return true;
}
modPtr2.priority = jj.intValue();
continue;
}
if (s1.equals("SET"))
{
ioPtr1 = modPtr2.setList;
parseNode();
continue;
}
System.out.println("ERROR: String '" + s1 + "' invalid function syntax");
return true;
}
return false;
}
/**
* Method to create a list of input nodes which are used for event
* driving the function.
*/
private void parseFuncInput(Func funcHead)
{
for(;;)
{
String s1 = getAName();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL") ||
s1.equals("I") || s1.equals("O") || s1.equals("T") || s1.equals("FANOUT") ||
s1.equals("LOAD") || s1.equals("PRIORITY") || s1.equals("SET"))
{
--iPtr;
break;
}
exPtr2 = new ALSExport();
exPtr2.nodePtr = null;
exPtr2.nodeName = s1;
funcHead.inList.add(exPtr2);
}
}
private Node dummyNode = new Node();
/**
* Method to create a list of output nodes for the function.
*/
private boolean parseFuncOutput()
{
for(;;)
{
String s1 = getAName();
if (s1 == null || s1.equals("GATE") || s1.equals("FUNCTION") || s1.equals("MODEL") ||
s1.equals("I") || s1.equals("O") || s1.equals("T") || s1.equals("FANOUT") ||
s1.equals("LOAD") || s1.equals("PRIORITY") || s1.equals("SET"))
{
--iPtr;
break;
}
boolean found = false;
for(Iterator<ALSExport> it = modPtr2.exList.iterator(); it.hasNext(); )
{
exPtr2 = it.next();
if (s1.equals(exPtr2.nodeName))
{
exPtr2.nodePtr = dummyNode;
found = true;
break;
}
}
if (!found)
{
System.out.println("ERROR: Unable to find node " + s1 + " in port list");
return true;
}
}
return false;
}
/**
* Method to get one string from the instruction buffer.
* The procedure returns a null value if End Of File is encountered.
*/
private String getAString()
{
while (instPtr[iPtr] < 0 || instBuf[instPtr[iPtr]] == '#')
{
if (netlistStringPoint >= netlistStrings.length)
{
++iPtr;
return null;
}
String line = netlistStrings[netlistStringPoint++];
fragmentLine(line);
iPtr = 0;
}
StringBuffer sb = new StringBuffer();
for(int i=instPtr[iPtr]; instBuf[i] != 0; i++)
sb.append(instBuf[i]);
++iPtr;
return sb.toString();
}
/**
* Method to read in the required number of strings to compose an
* integer value. It is possible to have a leading +/- sign before the actual
* integer value.
*/
private Integer getAnInt()
{
String s1 = getAString();
if (s1 == null) return null;
if (s1.startsWith("+") || s1.startsWith("-"))
{
String s2 = getAString();
if (s2 == null) return null;
s1 += s2;
}
return new Integer(TextUtils.atoi(s1));
}
/**
* Method to reads in the required number of strings to compose a
* float value. It is possible to have a leading +/- sign before the actual
* float value combined with the chance that the number is entered in scientific
* notation.
*/
private Double getADouble()
{
String s1 = getAString();
if (s1 == null) return null;
if (s1.startsWith("+") || s1.startsWith("-"))
{
String s2 = getAString();
if (s2 == null) return null;
s1 += s2;
}
if (!s1.endsWith("E"))
{
return new Double(TextUtils.atof(s1));
}
String s2 = getAString();
if (s2 == null) return null;
s1 += s2;
if (s2.startsWith("+") || s2.startsWith("-"))
{
String s3 = getAString();
if (s3 == null) return null;
s1 += s3;
}
return new Double(TextUtils.atof(s1));
}
/**
* Method to read in the required number of strings to compose a
* model/node name for the element. If array subscripting is used, the
* brackets and argument string is spliced to the node name.
*/
private String getAName()
{
String s1 = getAString();
if (s1 == null) return null;
String s2 = getAString();
if (s2 == null || !s2.startsWith("["))
{
--iPtr;
return s1;
}
s1 = s2;
for(;;)
{
s2 = getAString();
if (s2 == null) return null;
s1 = s2;
if (s2.startsWith("]")) break;
}
return s1;
}
/**
* Method to process the string specified by the calling argument
* and fragments it into a series of smaller character strings, each of which
* is terminated by a null character.
*/
private void fragmentLine(String line)
{
int j = 0, count = 0;
instPtr[0] = 0;
int k = 1;
for (int i = 0; ; ++i)
{
if (j > iBufSize - 3)
{
int newSize = iBufSize * 5;
char [] newBuf = new char[newSize];
for(int x=0; x<iBufSize; x++) newBuf[x] = instBuf[x];
instBuf = newBuf;
iBufSize = newSize;
}
if (k > iPtrSize - 2)
{
int newSize = iPtrSize * 5;
int [] newBuf = new int[newSize];
for(int x=0; x<iPtrSize; x++) newBuf[x] = instPtr[x];
instPtr = newBuf;
iPtrSize = newSize;
}
if (i >= line.length())
{
if (count != 0)
{
instBuf[j] = 0;
instPtr[k] = -1;
} else
{
instPtr[k-1] = -1;
}
break;
}
char chr = line.charAt(i);
switch (chr)
{
case ' ':
case ',':
case '\t':
case ':':
if (count != 0)
{
instBuf[j] = 0;
instPtr[k] = j+1;
++j;
++k;
count = 0;
}
break;
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case '=':
case '!':
case '>':
case '<':
case '+':
case '-':
case '*':
case '/':
case '%':
case '@':
case ';':
case '#':
if (count != 0)
{
instBuf[j] = 0;
instBuf[j+1] = chr;
instBuf[j+2] = 0;
instPtr[k] = j+1;
instPtr[k+1] = j+3;
j += 3;
k += 2;
count = 0;
} else
{
instBuf[j] = chr;
instBuf[j+1] = 0;
instPtr[k] = j+2;
j += 2;
++k;
}
break;
default:
instBuf[j] = Character.toUpperCase(chr);
++j;
++count;
}
}
}
}