/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Analyzer.java
* IRSIM simulator
* Translated by Steven M. Rubin, Sun Microsystems.
*
* Copyright (C) 1988, 1990 Stanford University.
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. Stanford University
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
package com.sun.electric.plugins.irsim;
import com.sun.electric.database.geometry.GenMath;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.io.FileType;
import com.sun.electric.tool.io.output.IRSIM;
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;
/**
* The Analyzer class is the top-level class for IRSIM simulation.
* By creating an Analyzer object, all other simulation objects are defined.
*
* Analyzers have Sim objects in them.
* Sim objects have Config and Eval objects in them.
*/
public class Analyzer extends Engine
{
private static final String simVersion = "9.5j";
// the meaning of SimVector.command
/** a comment in the command file */ private static final int VECTORCOMMENT = 1;
/** the "!" command to print gate info */ private static final int VECTOREXCL = 2;
/** the "?" command to print source/drain info */ private static final int VECTORQUESTION = 3;
/** the "activity" command */ private static final int VECTORACTIVITY = 4;
/** the "alias" command */ private static final int VECTORALIAS = 5;
/** the "ana" command */ private static final int VECTORANALYZER = 6;
/** the "assert" command (test signal value) */ private static final int VECTORASSERT = 7;
/** the "assertWhen" command */ private static final int VECTORASSERTWHEN = 8;
/** the "back" command */ private static final int VECTORBACK = 9;
/** the "c" command to run a clock cycle */ private static final int VECTORC = 10;
/** the "changes" command */ private static final int VECTORCHANGES = 11;
/** the "clock" command to declare stimuli */ private static final int VECTORCLOCK = 12;
/** the "debug" command */ private static final int VECTORDEBUG = 13;
/** the "decay" command */ private static final int VECTORDECAY = 14;
/** the "h" command (set signal high) */ private static final int VECTORH = 15;
/** the "inputs" command */ private static final int VECTORINPUTS = 16;
/** the "l" command (set signal low) */ private static final int VECTORL = 17;
/** the "model" command */ private static final int VECTORMODEL = 18;
/** the "p" command */ private static final int VECTORP = 19;
/** the "path" command */ private static final int VECTORPATH = 20;
/** the "print" command */ private static final int VECTORPRINT = 21;
/** the "printx" command */ private static final int VECTORPRINTX = 22;
/** the "R" command */ private static final int VECTORR = 23;
/** the "report" command */ private static final int VECTORREPORT = 24;
/** the "s" command (advance time) */ private static final int VECTORS = 25;
/** the "set" command to change vector values */ private static final int VECTORSET = 26;
/** the "stats" command */ private static final int VECTORSTATS = 27;
/** the "stepsize" command to set time advance */ private static final int VECTORSTEPSIZE = 28;
/** the "stop" command */ private static final int VECTORSTOP = 29;
/** the "t" command to trace */ private static final int VECTORT = 30;
/** the "tcap" command */ private static final int VECTORTCAP = 31;
/** the "u" command */ private static final int VECTORU = 32;
/** the "unitdelay" command */ private static final int VECTORUNITDELAY = 33;
/** the "until" command */ private static final int VECTORUNTIL = 34;
/** the "V" command */ private static final int VECTORV = 35;
/** the "vector" command to group signals */ private static final int VECTORVECTOR = 36;
/** the "x" command (set signal undefined) */ private static final int VECTORX = 37;
/** default simulation steps per screen */ private static final int DEF_STEPS = 4;
/** initial size of simulation window: 10ns */ private static final double DEFIRSIMTIMERANGE = 10.0E-9f;
/** number of buckets in histogram */ private static final int NBUCKETS = 20;
/** maximum width of print line */ private static final int MAXCOL = 80;
/** set of potential characters */ private static final String potChars = "luxh.";
/** scale factor for resolution */ private static final long resolutionScale = 1000;
/** 1 -> 1ns, 100 -> 0.01ns resolution, etc */
/** time values in command file are in ns */ private static final double cmdFileUnits = 0.000000001;
/**
* Class that defines a single low-level IRSIM control command.
*/
private static class SimVector
{
/** index of command */ int command;
/** parameters to the command */ String [] parameters;
/** actual signals named in command */ List<DigitalSignal> sigs;
/** negated signals named in command */ List<DigitalSignal> sigsNegated;
/** duration of step, where appropriate */ double value;
/** next in list of vectors */ SimVector next;
}
public static class AssertWhen
{
/** which node we will check */ Sim.Node node;
/** what value has the node */ char val;
/** next in list of assertions */ AssertWhen nxt;
}
private static class Sequence
{
/** signal to control */ DigitalSignal sig;
/** array of values */ String [] values;
}
private SimVector firstVector = null;
private SimVector lastVector = null;
private long stepSize = 50000;
private long firstTime;
private long lastTime;
private long startTime;
private long stepsTime;
private long endTime;
private long lastStart; /** last redisplay starting time */
private double [] traceTime;
private short [] traceState;
private int traceTotal = 0;
/** vectors which make up clock */ private List<Sequence> xClock;
/** vectors which make up a sequence */ private List<Sequence> sList;
/** longest clock sequence defined */ private int maxClock = 0;
/** current output column */ private int column = 0;
private List [] listTbl = new List[5];
/** list of nodes to be driven high */ public List<Sim.Node> hInputs = new ArrayList<Sim.Node>();
/** list of nodes to be driven low */ public List<Sim.Node> lIinputs = new ArrayList<Sim.Node>();
/** list of nodes to be driven X */ public List<Sim.Node> uInputs = new ArrayList<Sim.Node>();
/** list of nodes to be removed from input */ public List<Sim.Node> xInputs = new ArrayList<Sim.Node>();
/** set when analyzer is running */ public boolean analyzerON;
/** the simulation engine */ private Sim theSim;
/** the waveform window */ private WaveformWindow ww;
/** the analysis data being displayed */ private DigitalAnalysis analysis;
/** the cell being simulated */ private Cell cell;
/** the context for the cell being simulated */ private VarContext context;
/** the name of the file being simulated */ private String fileName;
/** the name of the last vector file read */ private String vectorFileName;
/** mapping from signals to nodes */ private HashMap<DigitalSignal,Sim.Node> nodeMap;
/************************** ELECTRIC INTERFACE **************************/
Analyzer()
{
theSim = new Sim(this);
}
/**
* Main entry point to start simulating a cell.
* @param cell the cell to simulate.
* @param fileName the file with the input deck (null to generate one)
*/
public static void simulateCell(Cell cell, VarContext context, String fileName)
{
Analyzer theAnalyzer = new Analyzer();
theAnalyzer.cell = cell;
theAnalyzer.context = context;
theAnalyzer.fileName = fileName;
startIrsim(theAnalyzer);
}
private static void startIrsim(Analyzer analyzer)
{
synchronized(analyzer)
{
System.out.println("IRSIM, version " + simVersion);
// now initialize the simulator
analyzer.initRSim();
// Load network
if (analyzer.cell != null) System.out.println("Loading netlist for " + analyzer.cell + "..."); else
System.out.println("Loading netlist for file " + analyzer.fileName + "...");
analyzer.loadCircuit();
Stimuli sd = analyzer.analysis.getStimuli();
Simulation.showSimulationData(sd, null);
// make a waveform window
analyzer.ww = sd.getWaveformWindow();
analyzer.ww.setDefaultHorizontalRange(0.0, DEFIRSIMTIMERANGE);
analyzer.ww.setMainXPositionCursor(DEFIRSIMTIMERANGE/5.0*2.0);
analyzer.ww.setExtensionXPositionCursor(DEFIRSIMTIMERANGE/5.0*3.0);
analyzer.init();
}
}
private void init()
{
// tell the simulator to watch all signals
initTimes(0, 50000, theSim.curDelta);
for(Sim.Node n : theSim.getNodeList())
{
while ((n.nFlags & Sim.ALIAS) != 0)
n = n.nLink;
if ((n.nFlags & Sim.MERGED) != 0)
System.out.println("can't watch node " + n.nName);
n.wind = n.cursor = n.head;
}
updateWindow(0);
lastStart = theSim.maxTime;
analyzerON = true;
// read signal values
updateWindow(theSim.curDelta);
}
private void loadCircuit()
{
// Load network
List<Object> components = null;
URL fileURL = null;
if (fileName == null)
{
// generate the components directly
components = IRSIM.getIRSIMComponents(cell, context);
} else
{
// get a pointer to to the file with the network (.sim file)
fileURL = TextUtils.makeURLToFile(fileName);
}
if (theSim.readNetwork(fileURL, components)) return;
// convert the stimuli
Stimuli sd = new Stimuli();
sd.setDataType(FileType.IRSIM);
sd.setEngine(this);
analysis = new DigitalAnalysis(sd, true);
sd.setSeparatorChar('/');
sd.setCell(cell);
nodeMap = new HashMap<DigitalSignal,Sim.Node>();
for(Sim.Node n : theSim.getNodeList())
{
if (n.nName.equalsIgnoreCase("vdd") || n.nName.equalsIgnoreCase("gnd")) continue;
// make a signal for it
DigitalSignal sig = new DigitalSignal(analysis);
n.sig = sig;
int slashPos = n.nName.lastIndexOf('/');
if (slashPos >= 0)
{
sig.setSignalName(n.nName.substring(slashPos+1), n.nName.substring(0, slashPos));
} else
{
sig.setSignalName(n.nName, null);
}
nodeMap.put(sig, n);
sig.buildTime(2);
sig.buildState(2);
sig.setTime(0, 0);
sig.setTime(1, 0.00000001);
sig.setState(0, 0);
sig.setState(1, 0);
}
}
/**
* Method to update the simulation (because some stimuli have changed).
*/
public void update()
{
playVectors();
}
/**
* Method to set the currently-selected signal high at the current time.
*/
public void setSignalHigh()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal before setting it High",
"No Signals Selected");
return;
}
String [] parameters = new String[1];
for(Signal sig : signals)
{
parameters[0] = sig.getFullName().replace('.', '/');
newVector(VECTORH, parameters, ww.getMainXPositionCursor(), false);
}
if (Simulation.isBuiltInResimulateEach())
playVectors();
}
/**
* Method to set the currently-selected signal low at the current time.
*/
public void setSignalLow()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal before setting it Low",
"No Signals Selected");
return;
}
String [] parameters = new String[1];
for(Signal sig : signals)
{
parameters[0] = sig.getFullName().replace('.', '/');
newVector(VECTORL, parameters, ww.getMainXPositionCursor(), false);
}
if (Simulation.isBuiltInResimulateEach())
playVectors();
}
/**
* Method to set the currently-selected signal to have a clock with a given period.
*/
public void setClock(double period)
{
System.out.println("IRSIM CANNOT HANDLE CLOCKS YET");
}
/**
* Method to set the currently-selected signal undefined at the current time.
*/
public void setSignalX()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() == 0)
{
Job.getUserInterface().showErrorMessage("Must select a signal before setting it Undefined",
"No Signals Selected");
return;
}
String [] parameters = new String[1];
for(Signal sig : signals)
{
parameters[0] = sig.getFullName().replace('.', '/');
newVector(VECTORX, parameters, ww.getMainXPositionCursor(), false);
}
if (Simulation.isBuiltInResimulateEach())
playVectors();
}
/**
* 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)
{
SimVector excl = new SimVector();
excl.command = VECTOREXCL;
excl.sigs = new ArrayList<DigitalSignal>();
excl.sigs.add((DigitalSignal)sig);
issueCommand(excl);
excl.command = VECTORQUESTION;
issueCommand(excl);
}
}
/**
* Method to remove all stimuli from the currently-selected signal.
*/
public void removeStimuliFromSignal()
{
List<Signal> signals = ww.getHighlightedNetworkNames();
if (signals.size() != 1)
{
Job.getUserInterface().showErrorMessage("Must select a single signal on which to clear stimuli",
"No Signals Selected");
return;
}
Signal sig = signals.get(0);
sig.clearControlPoints();
SimVector lastSV = null;
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
if (sv.command == VECTORL || sv.command == VECTORH || sv.command == VECTORX ||
sv.command == VECTORASSERT || sv.command == VECTORSET)
{
if (sv.sigs.contains(sig))
{
if (lastSV == null)
firstVector = sv.next; else
lastSV.next = sv.next;
continue;
}
}
lastSV = sv;
}
lastVector = lastSV;
if (Simulation.isBuiltInResimulateEach())
playVectors();
}
/**
* 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++)
{
if (clearControlPoint(ws.getSignal(), selectedCPs[i]))
found = true;
}
}
}
if (!found)
{
System.out.println("There are no selected control points to remove");
return false;
}
// resimulate if requested
if (Simulation.isBuiltInResimulateEach())
playVectors();
return true;
}
/**
* Method to remove all stimuli from the simulation.
*/
public void removeAllStimuli()
{
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel wp = it.next();
for(WaveSignal ws : wp.getSignals())
{
ws.getSignal().clearControlPoints();
}
}
if (Simulation.isBuiltInResimulateEach())
clearAllVectors();
}
/**
* Method to save the current stimuli information to disk.
*/
public void saveStimuli()
{
saveVectorFile();
}
/**
* Method to restore the current stimuli information from disk.
*/
public void restoreStimuli()
{
vectorFileName = OpenFile.chooseInputFile(FileType.IRSIMVECTOR, "IRSIM Vector file");
if (vectorFileName == null) return;
loadVectorFile();
}
/**
* Method to reload the circuit data.
*/
public void refresh()
{
// make a new simulation object
theSim = new Sim(this);
// now initialize the simulator
initRSim();
// Load network
loadCircuit();
Simulation.showSimulationData(analysis.getStimuli(), ww);
if (vectorFileName != null) loadVectorFile();
init();
playVectors();
}
/************************** SIMULATION VECTORS **************************/
/**
* Method to play the simulation vectors into the simulator.
*/
private void playVectors()
{
SimVector back = new SimVector();
back.command = VECTORBACK;
back.value = 0;
issueCommand(back);
// issueCommand("flush", null);
double curTime = 0;
analyzerON = false;
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
if (sv.command == VECTORCOMMENT) continue;
issueCommand(sv);
}
SimVector step = new SimVector();
step.command = VECTORS;
step.value = Sim.deltaToNS(stepSize);
issueCommand(step);
analyzerON = true;
updateWindow(theSim.curDelta);
// update main cursor location if requested
if (Simulation.isBuiltInAutoAdvance())
ww.setMainXPositionCursor(curTime + 10.0/1000000000.0);
}
/**
* Method to clear all simulation vectors.
*/
private void clearAllVectors()
{
firstVector = null;
lastVector = null;
playVectors();
}
/**
* Method to read simulation vectors from a file.
*/
private void loadVectorFile()
{
URL url = TextUtils.makeURLToFile(vectorFileName);
try
{
URLConnection urlCon = url.openConnection();
InputStreamReader is = new InputStreamReader(urlCon.getInputStream());
LineNumberReader lineReader = new LineNumberReader(is);
// remove all vectors
firstVector = null;
lastVector = null;
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel wp = it.next();
for(WaveSignal ws : wp.getSignals())
{
ws.getSignal().clearControlPoints();
}
}
System.out.println("Reading " + vectorFileName);
double currentTime = 0;
boolean anyAnalyzerCommands = false;
for(;;)
{
String buf = lineReader.readLine();
if (buf == null) break;
// ignore comments
if (buf.startsWith("|"))
{
String [] par = new String[1];
par[0] = buf.substring(1);
newVector(VECTORCOMMENT, par, currentTime, true);
continue;
}
// get the first keyword
String [] targ = Sim.parseLine(buf, false);
if (targ == null || targ.length <= 0) continue;
// handle commands
int command;
if (targ[0].equals("!")) command = VECTOREXCL; else
if (targ[0].equals("?")) command = VECTORQUESTION; else
if (targ[0].equals("activity")) command = VECTORACTIVITY; else
if (targ[0].equals("alias")) command = VECTORALIAS; else
if (targ[0].equals("ana") || targ[0].equals("analyzer")) command = VECTORANALYZER; else
if (targ[0].equals("assert")) command = VECTORASSERT; else
if (targ[0].equals("assertwhen")) command = VECTORASSERTWHEN; else
if (targ[0].equals("back")) command = VECTORBACK; else
if (targ[0].equals("c")) command = VECTORC; else
if (targ[0].equals("changes")) command = VECTORCHANGES; else
if (targ[0].equals("clock")) command = VECTORCLOCK; else
if (targ[0].equals("debug")) command = VECTORDEBUG; else
if (targ[0].equals("decay")) command = VECTORDECAY; else
if (targ[0].equals("h")) command = VECTORH; else
if (targ[0].equals("inputs")) command = VECTORINPUTS; else
if (targ[0].equals("l")) command = VECTORL; else
if (targ[0].equals("model")) command = VECTORMODEL; else
if (targ[0].equals("p")) command = VECTORP; else
if (targ[0].equals("path")) command = VECTORPATH; else
if (targ[0].equals("print")) command = VECTORPRINT; else
if (targ[0].equals("printx")) command = VECTORPRINTX; else
if (targ[0].equals("R")) command = VECTORR; else
if (targ[0].equals("report")) command = VECTORREPORT; else
if (targ[0].equals("s")) command = VECTORS; else
if (targ[0].equals("set")) command = VECTORSET; else
if (targ[0].equals("stats")) command = VECTORSTATS; else
if (targ[0].equals("stepsize")) command = VECTORSTEPSIZE; else
if (targ[0].equals("stop")) command = VECTORSTOP; else
if (targ[0].equals("t")) command = VECTORT; else
if (targ[0].equals("tcap")) command = VECTORTCAP; else
if (targ[0].equals("u")) command = VECTORU; else
if (targ[0].equals("unitdelay")) command = VECTORUNITDELAY; else
if (targ[0].equals("until")) command = VECTORUNTIL; else
if (targ[0].equals("V")) command = VECTORV; else
if (targ[0].equals("vector")) command = VECTORVECTOR; else
if (targ[0].equals("x")) command = VECTORX; else
{
System.out.println("Unknown command: " + targ[0]);
continue;
}
// store the vector
String [] params = new String[targ.length-1];
for(int i=1; i<targ.length; i++) params[i-1] = targ[i];
SimVector sv = newVector(command, params, currentTime, true);
// keep track of time
if (command == VECTORS)
{
if (sv == null) continue;
currentTime += sv.value * cmdFileUnits;
continue;
}
// handle changes to signals in the Waveform Window
if (command == VECTORANALYZER)
{
if (!anyAnalyzerCommands)
{
// clear the stimuli on the first time
anyAnalyzerCommands = true;
ww.clearHighlighting();
List<Panel> allPanels = new ArrayList<Panel>();
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
allPanels.add(it.next());
for(Panel wp : allPanels)
{
wp.closePanel();
}
}
List<DigitalSignal> sigs = new ArrayList<DigitalSignal>();
getTargetNodes(targ, 1, sigs, null);
for(Signal sig : sigs)
{
Panel wp = new Panel(ww, false, analysis.getAnalysisType());
wp.makeSelectedPanel(-1, -1);
new WaveSignal(wp, sig);
}
continue;
}
// handle aggregation of signals into busses
if (command == VECTORVECTOR)
{
// find this vector name in the list of vectors
DigitalSignal busSig = null;
for(Signal aSig : analysis.getBussedSignals())
{
DigitalSignal sig = (DigitalSignal)aSig;
if (sig.getSignalName().equals(targ[1]))
{
busSig = sig;
busSig.clearBussedSignalList();
break;
}
}
if (busSig == null)
{
busSig = new DigitalSignal(analysis);
busSig.setSignalName(targ[1], null);
busSig.buildBussedSignalList();
}
List<DigitalSignal> sigs = new ArrayList<DigitalSignal>();
getTargetNodes(targ, 2, sigs, null);
for(DigitalSignal sig : sigs)
{
busSig.addToBussedSignalList(sig);
}
continue;
}
}
playVectors();
updateWindow(theSim.curDelta);
lineReader.close();
} catch (IOException e)
{
System.out.println("Error reading " + vectorFileName);
return;
}
}
/**
* Method to save simulation vectors to file "filename" (if zero, prompt for file).
*/
private void saveVectorFile()
{
String fileName = OpenFile.chooseOutputFile(FileType.IRSIMVECTOR, "IRSIM Vector file", Library.getCurrent().getName() + ".cmd");
if (fileName == null) return;
try
{
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
String infstr = commandName(sv.command);
for(int i=0; i<sv.parameters.length; i++)
infstr += " " + sv.parameters[i];
printWriter.println(infstr);
}
printWriter.close();
System.out.println("Wrote " + fileName);
} catch (IOException e)
{
System.out.println("Error writing " + fileName);
return;
}
}
private void issueCommand(SimVector sv)
{
if (Simulation.isIRSIMShowsCommands())
{
System.out.print("> " + commandName(sv.command));
if (sv.parameters != null)
{
for(int i=0; i<sv.parameters.length; i++) System.out.print(" " + sv.parameters[i]);
}
System.out.println();
}
switch (sv.command)
{
case VECTOREXCL: doInfo(sv); break;
case VECTORQUESTION: doInfo(sv); break;
case VECTORACTIVITY: doActivity(sv); break;
case VECTORALIAS: doPrintAlias(); break;
case VECTORANALYZER: break;
case VECTORASSERT: doAssert(sv); break;
case VECTORASSERTWHEN: doAssertWhen(sv); break;
case VECTORBACK: doBack(sv); break;
case VECTORC: doClock(sv); break;
case VECTORCHANGES: doChanges(sv); break;
case VECTORCLOCK: setAClock(sv); break;
case VECTORDEBUG: doDebug(sv); break;
case VECTORDECAY: doDecay(sv); break;
case VECTORH: doSetValue(sv); break;
case VECTORINPUTS: doInputs(); break;
case VECTORL: doSetValue(sv); break;
case VECTORMODEL: doModel(sv); break;
case VECTORP: doPhase(); break;
case VECTORPATH: doPath(sv); break;
case VECTORPRINT: doPrint(sv); break;
case VECTORPRINTX: doPrintX(); break;
case VECTORR: doRunSeq(sv); break;
case VECTORREPORT: doReport(sv); break;
case VECTORS: doStep(sv); break;
case VECTORSET: doSet(sv); break;
case VECTORSTATS: doStats(sv); break;
case VECTORSTEPSIZE: doStepSize(sv); break;
case VECTORSTOP: doStop(sv); break;
case VECTORT: doTrace(sv); break;
case VECTORTCAP: doTCap(); break;
case VECTORU: doSetValue(sv); break;
case VECTORUNITDELAY: doUnitDelay(sv); break;
case VECTORUNTIL: doUntil(sv); break;
case VECTORV: doV(sv); break;
case VECTORVECTOR: break;
case VECTORX: doSetValue(sv); break;
}
}
private String commandName(int command)
{
switch (command)
{
case VECTORCOMMENT: return "|";
case VECTOREXCL: return "!";
case VECTORQUESTION: return "?";
case VECTORACTIVITY: return "activity";
case VECTORALIAS: return "alias";
case VECTORANALYZER: return "ana";
case VECTORASSERT: return "assert";
case VECTORASSERTWHEN: return "assertWhen";
case VECTORBACK: return "back";
case VECTORC: return "c";
case VECTORCHANGES: return "changes";
case VECTORCLOCK: return "clock";
case VECTORDEBUG: return "debug";
case VECTORDECAY: return "decay";
case VECTORH: return "h";
case VECTORINPUTS: return "inputs";
case VECTORL: return "l";
case VECTORMODEL: return "model";
case VECTORP: return "p";
case VECTORPATH: return "path";
case VECTORPRINT: return "print";
case VECTORPRINTX: return "printx";
case VECTORR: return "R";
case VECTORREPORT: return "report";
case VECTORS: return "s";
case VECTORSET: return "set";
case VECTORSTATS: return "stats";
case VECTORSTEPSIZE: return "stepsize";
case VECTORSTOP: return "stop";
case VECTORT: return "t";
case VECTORTCAP: return "tcap";
case VECTORU: return "u";
case VECTORUNITDELAY: return "unitdelay";
case VECTORUNTIL: return "until";
case VECTORV: return "V";
case VECTORVECTOR: return "vector";
case VECTORX: return "x";
}
return "";
}
/**
* Method to create a new simulation vector at time "time", on signal "sig",
* with state "state". The vector is inserted into the play list in the proper
* order.
*/
private SimVector newVector(int command, String [] params, double insertTime, boolean justAppend)
{
SimVector newsv = new SimVector();
newsv.command = command;
newsv.parameters = params;
// precompute information that is appropriate to this command
switch (command)
{
case VECTORS:
double newSize = Sim.deltaToNS(stepSize);
if (params.length > 0)
{
newSize = TextUtils.atof(params[0]);
long lNewSize = Sim.nsToDelta(newSize);
if (lNewSize <= 0)
{
System.out.println("Bad step size: " + TextUtils.formatDouble(newSize*1000) + "psec (must be 10 psec or larger), ignoring");
return null;
}
}
newsv.value = newSize;
break;
case VECTORSTEPSIZE:
if (params.length > 0)
stepSize = Sim.nsToDelta(TextUtils.atof(params[0]));
break;
case VECTORBACK:
newsv.value = 0;
if (params.length > 0)
{
newsv.value = TextUtils.atof(params[0]);
}
break;
case VECTORL:
case VECTORH:
case VECTORX:
case VECTORANALYZER:
case VECTOREXCL:
case VECTORQUESTION:
case VECTORT:
case VECTORPATH:
case VECTORSTOP:
newsv.sigs = new ArrayList<DigitalSignal>();
newsv.sigsNegated = null;
if (command == VECTORT) newsv.sigsNegated = new ArrayList<DigitalSignal>();
getTargetNodes(params, 0, newsv.sigs, newsv.sigsNegated);
if (command == VECTORL || command == VECTORH || command == VECTORX)
{
// add this moment in time to the control points for the signal
for(Signal sig : newsv.sigs)
{
sig.addControlPoint(insertTime);
}
}
break;
}
// insert the vector */
SimVector lastSV = null;
if (justAppend || insertTime < 0.0)
{
lastSV = lastVector;
} else
{
double defaultStepSize = 10.0 * cmdFileUnits;
double curTime = 0.0;
int clockPhases = 0;
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
switch (sv.command)
{
case VECTORS:
double stepSze = sv.value * cmdFileUnits;
long ss = Sim.nsToDelta(((curTime + stepSze) - insertTime) / cmdFileUnits);
if (ss != 0 && GenMath.doublesLessThan(insertTime, curTime+stepSze))
{
// splitting step at "insertTime"
sv.parameters = new String[1];
sv.value = (insertTime-curTime) / cmdFileUnits;
sv.parameters[0] = TextUtils.formatDouble(sv.value);
// create second step to advance after this signal
SimVector afterSV = new SimVector();
afterSV.command = VECTORS;
afterSV.parameters = new String[1];
afterSV.value = (curTime + stepSze - insertTime) / cmdFileUnits;
afterSV.parameters[0] = TextUtils.formatDouble(afterSV.value);
afterSV.next = sv.next;
sv.next = afterSV;
}
curTime += stepSze;
break;
case VECTORSTEPSIZE:
if (sv.parameters.length > 0)
defaultStepSize = TextUtils.atof(sv.parameters[0]) * cmdFileUnits;
break;
case VECTORCLOCK:
clockPhases = sv.parameters.length - 1;
break;
case VECTORC:
int mult = 1;
if (sv.parameters.length > 0)
mult = TextUtils.atoi(sv.parameters[0]);
curTime += defaultStepSize * clockPhases * mult;
break;
case VECTORP:
curTime += defaultStepSize;
break;
}
lastSV = sv;
if (!GenMath.doublesLessThan(curTime, insertTime)) break;
}
if (GenMath.doublesLessThan(curTime, insertTime))
{
// create step to advance to the insertion time
double thisStep = (insertTime-curTime) / cmdFileUnits;
if (thisStep > 0.005)
{
SimVector afterSV = new SimVector();
afterSV.command = VECTORS;
afterSV.parameters = new String[1];
afterSV.parameters[0] = TextUtils.formatDouble(thisStep);
// afterSV.parameters[0] = TextUtils.formatDouble(thisStep / cmdFileUnits);
afterSV.value = thisStep;
if (lastSV == null)
{
afterSV.next = firstVector;
firstVector = afterSV;
} else
{
afterSV.next = lastSV.next;
lastSV.next = afterSV;
}
lastSV = afterSV;
}
}
}
if (lastSV == null)
{
newsv.next = firstVector;
firstVector = newsv;
} else
{
newsv.next = lastSV.next;
lastSV.next = newsv;
}
if (newsv.next == null)
{
lastVector = newsv;
}
return newsv;
}
private boolean clearControlPoint(Signal sig, double insertTime)
{
double defaultStepSize = 10.0 * cmdFileUnits;
double curTime = 0.0;
int clockPhases = 0;
SimVector lastSV = null;
boolean cleared = false;
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
switch (sv.command)
{
case VECTORS:
double stepSze = defaultStepSize;
if (sv.value != 0) stepSze = sv.value * cmdFileUnits;
curTime += stepSze;
break;
case VECTORSTEPSIZE:
if (sv.parameters.length > 0)
defaultStepSize = TextUtils.atof(sv.parameters[0]) * cmdFileUnits;
break;
case VECTORCLOCK:
clockPhases = sv.parameters.length - 1;
break;
case VECTORC:
int mult = 1;
if (sv.parameters.length > 0)
mult = TextUtils.atoi(sv.parameters[0]);
curTime += defaultStepSize * clockPhases * mult;
break;
case VECTORP:
curTime += defaultStepSize;
break;
case VECTORL:
case VECTORH:
case VECTORX:
if (GenMath.doublesEqual(insertTime, curTime))
{
boolean found = false;
for(Signal s : sv.sigs)
{
if (s == sig)
{
found = true;
sig.removeControlPoint(insertTime);
break;
}
}
if (found)
{
cleared = true;
if (lastSV == null) firstVector = sv.next; else
lastSV.next = sv.next;
continue;
}
}
}
lastSV = sv;
if (GenMath.doublesLessThan(insertTime, curTime)) break;
}
return cleared;
}
private void getTargetNodes(String [] params, int low, List<DigitalSignal> normalList, List<DigitalSignal> negatedList)
{
int size = params.length - low;
for(int i=0; i<size; i++)
{
String name = params[i+low];
boolean negated = false;
if (name.startsWith("-"))
{
name = name.substring(1);
if (negatedList != null) negated = true;
}
if (name.indexOf('*') >= 0)
{
for(DigitalSignal sig : analysis.getSignals())
{
if (strMatch(name, sig.getFullName()))
{
if (negated) negatedList.add(sig); else
normalList.add(sig);
}
}
} else
{
// no wildcards: just find the name
DigitalSignal sig = this.findName(name);
if (sig == null)
{
System.out.println("Cannot find node named '" + name + "'");
continue;
}
if (negated) negatedList.add(sig); else
normalList.add(sig);
}
}
}
/**
* Method to examine the test vectors and determine the ending simulation time.
*/
private double getEndTime()
{
double defaultStepSize = 10.0 * cmdFileUnits;
double curTime = 0.0;
int clockPhases = 0;
for(SimVector sv = firstVector; sv != null; sv = sv.next)
{
switch (sv.command)
{
case VECTORS:
double stepSze = defaultStepSize;
if (sv.value != 0) stepSze = sv.value * cmdFileUnits;
curTime += stepSze;
break;
case VECTORSTEPSIZE:
if (sv.parameters.length > 0)
defaultStepSize = TextUtils.atof(sv.parameters[0]) * cmdFileUnits;
break;
case VECTORCLOCK:
clockPhases = sv.parameters.length - 1;
break;
case VECTORC:
int mult = 1;
if (sv.parameters.length > 0)
mult = TextUtils.atoi(sv.parameters[0]);
curTime += defaultStepSize * clockPhases * mult;
break;
case VECTORP:
curTime += defaultStepSize;
break;
}
}
return curTime;
}
/******************************************** COMMANDS *****************************************/
/**
* display info about a node
*/
private void doInfo(SimVector sv)
{
if (sv.sigs == null) return;
for(Signal sig : sv.sigs)
{
Sim.Node n = nodeMap.get(sig);
if (n == null) continue;
String name = n.nName;
while((n.nFlags & Sim.ALIAS) != 0)
n = n.nLink;
if ((n.nFlags & Sim.MERGED) != 0)
{
System.out.println(name + " => node is inside a transistor stack");
return;
}
String infstr = "";
infstr += pValue(name, n);
if ((n.nFlags & Sim.INPUT) != 0)
infstr += "[NOTE: node is an input] ";
infstr += "(vl=" + n.vLow + " vh=" + n.vHigh + ") ";
if ((n.nFlags & Sim.USERDELAY) != 0)
infstr += "(tpLH=" + n.tpLH + ", tpHL=" + n.tpHL + ") ";
infstr += "(" + n.nCap + " pf) ";
System.out.println(infstr);
infstr = "";
if (sv.command == VECTOREXCL)
{
infstr += "is computed from:";
for(Sim.Trans t : n.nTermList)
{
infstr += " ";
if (theSim.irDebug == 0)
{
String drive = null;
Sim.Node rail = (t.drain.nFlags & Sim.POWER_RAIL) != 0 ? t.drain : t.source;
if (Sim.baseType(t.tType) == Sim.NCHAN && rail == theSim.groundNode)
drive = "pulled down by ";
else if (Sim.baseType(t.tType) == Sim.PCHAN && rail == theSim.powerNode)
drive = "pulled up by ";
else if (Sim.baseType(t.tType) == Sim.DEP && rail == theSim.powerNode &&
Sim.otherNode(t, rail) == t.gate)
drive = "pullup ";
else
infstr += pTrans(t);
if (drive != null)
{
infstr += drive;
infstr += pGValue(t);
infstr += prTRes(t.r);
if (t.tLink != t && (theSim.tReport & Sim.REPORT_TCOORD) != 0)
infstr += " <" + t.x + "," + t.y + ">";
}
} else
{
infstr += pTrans(t);
}
}
} else
{
infstr += "affects:";
for(Sim.Trans t : n.nGateList)
{
infstr += pTrans(t);
}
}
System.out.println(infstr);
if (n.events != null)
{
System.out.println("Pending events:");
for(Eval.Event e = n.events; e != null; e = e.nLink)
System.out.println(" transition to " + Sim.vChars.charAt(e.eval) + " at " + Sim.deltaToNS(e.nTime)+ "ns");
}
}
}
/**
* print histogram of circuit activity in specified time interval
*/
private void doActivity(SimVector sv)
{
long begin = Sim.nsToDelta(TextUtils.atof(sv.parameters[0]));
long end = theSim.curDelta;
if (sv.parameters.length > 1)
end = Sim.nsToDelta(TextUtils.atof(sv.parameters[1]));
if (end < begin)
{
long swp = end; end = begin; begin = swp;
}
// collect histogram info by walking the network
long [] table = new long[NBUCKETS];
for(int i = 0; i < NBUCKETS; table[i++] = 0);
long size = (end - begin + 1) / NBUCKETS;
if (size <= 0) size = 1;
for(Sim.Node n : theSim.getNodeList())
{
if ((n.nFlags & (Sim.ALIAS | Sim.MERGED | Sim.POWER_RAIL)) == 0)
{
if (n.getTime() >= begin && n.getTime() <= end)
table[(int)((n.getTime() - begin) / size)] += 1;
}
}
// print out what we found
int total = 0;
for(int i = 0; i < NBUCKETS; i++) total += table[i];
System.out.println("Histogram of circuit activity: " + Sim.deltaToNS(begin) +
" . " + Sim.deltaToNS(end) + "ns (bucket size = " + Sim.deltaToNS(size) + ")");
for(int i = 0; i < NBUCKETS; i += 1)
System.out.println(" " + Sim.deltaToNS(begin + (i * size)) + " -" + Sim.deltaToNS(begin + (i + 1) * size) + table[i]);
}
/**
* Print nodes that are aliases
*/
private void doPrintAlias()
{
if (theSim.numAliases == 0)
System.out.println("there are no aliases");
else
{
System.out.println("there are " + theSim.numAliases + " aliases:");
for(Sim.Node n : theSim.getNodeList())
{
if ((n.nFlags & Sim.ALIAS) != 0)
{
n = unAlias(n);
String is_merge = (n.nFlags & Sim.MERGED) != 0 ? " (part of a stack)" : "";
System.out.println(" " + n.nName + " . " + n.nName + is_merge);
}
}
}
}
/**
* Move back simulation time to specified time.
*/
private void doBack(SimVector sv)
{
long newT = Sim.nsToDelta(sv.value);
if (newT < 0 || newT > theSim.curDelta)
{
System.out.println(sv.value + ": invalid time in BACK command");
return;
}
theSim.curDelta = newT;
clearInputs();
theSim.getModel().backSimTime(theSim.curDelta, 0);
theSim.curNode = null; // fudge
List<Sim.Node> nodes = theSim.getNodeList();
for(Sim.Node n : nodes)
{
theSim.backToTime(n);
}
if (theSim.curDelta == 0)
theSim.getModel().reInit();
if (analyzerON)
{
for(Sim.Node n : theSim.getNodeList())
{
n.wind = n.cursor = n.head;
}
// should set "theSim.curDelta" to the width of the screen
initTimes(0, stepsTime / DEF_STEPS, theSim.curDelta);
updateTraceCache();
}
pnWatchList();
}
/**
* process "c" command line
*/
private void doClock(SimVector sv)
{
// calculate how many clock cycles to run
int n = 1;
if (sv.parameters.length == 1)
{
n = TextUtils.atoi(sv.parameters[0]);
if (n <= 0) n = 1;
}
clockIt(n); // do the hard work
}
/**
* Print list of nodes which last changed value in specified time interval
*/
private void doChanges(SimVector sv)
{
long begin = Sim.nsToDelta(TextUtils.atof(sv.parameters[0]));
long end = theSim.curDelta;
if (sv.parameters.length > 1)
end = Sim.nsToDelta(TextUtils.atof(sv.parameters[1]));
column = 0;
System.out.print("Nodes with last transition in interval " + Sim.deltaToNS(begin) + " . " + Sim.deltaToNS(end) + "ns:");
for(Sim.Node n : theSim.getNodeList())
{
n = unAlias(n);
if ((n.nFlags & (Sim.MERGED | Sim.ALIAS)) != 0) return;
if (n.getTime() >= begin && n.getTime() <= end)
{
int i = n.nName.length() + 2;
if (column + i >= MAXCOL)
{
column = 0;
}
column += i;
System.out.print(" " + n.nName);
}
}
System.out.println();
}
/**
* define clock sequences(s)
*/
private void setAClock(SimVector sv)
{
// process sequence and add to clock list
defSequence(sv.parameters, xClock);
// compute the maximum clock size
maxClock = 0;
for(Sequence t : xClock)
{
if (t.values.length > maxClock) maxClock = t.values.length;
}
}
private void doDebug(SimVector sv)
{
if (sv.parameters.length <= 0) theSim.irDebug = 0; else
{
for(int i=0; i<sv.parameters.length; i++)
{
if (sv.parameters[i].equalsIgnoreCase("ev"))
{
theSim.irDebug |= Sim.DEBUG_EV;
} else if (sv.parameters[i].equalsIgnoreCase("dc"))
{
theSim.irDebug |= Sim.DEBUG_DC;
} else if (sv.parameters[i].equalsIgnoreCase("tau"))
{
theSim.irDebug |= Sim.DEBUG_TAU;
} else if (sv.parameters[i].equalsIgnoreCase("taup"))
{
theSim.irDebug |= Sim.DEBUG_TAUP;
} else if (sv.parameters[i].equalsIgnoreCase("spk"))
{
theSim.irDebug |= Sim.DEBUG_SPK;
} else if (sv.parameters[i].equalsIgnoreCase("tw"))
{
theSim.irDebug |= Sim.DEBUG_TW;
} else if (sv.parameters[i].equalsIgnoreCase("all"))
{
theSim.irDebug = Sim.DEBUG_EV | Sim.DEBUG_DC | Sim.DEBUG_TAU | Sim.DEBUG_TAUP | Sim.DEBUG_SPK | Sim.DEBUG_TW;
} else if (sv.parameters[i].equalsIgnoreCase("off"))
{
theSim.irDebug = 0;
}
}
}
System.out.print("Debugging");
if (theSim.irDebug == 0) System.out.println(" OFF"); else
{
if ((theSim.irDebug&Sim.DEBUG_EV) != 0) System.out.print(" event-scheduling");
if ((theSim.irDebug&Sim.DEBUG_DC) != 0) System.out.print(" final-value-computation");
if ((theSim.irDebug&Sim.DEBUG_TAU) != 0) System.out.print(" tau/delay-computation");
if ((theSim.irDebug&Sim.DEBUG_TAUP) != 0) System.out.print(" tauP-computation");
if ((theSim.irDebug&Sim.DEBUG_SPK) != 0) System.out.print(" spike-analysis");
if ((theSim.irDebug&Sim.DEBUG_TW) != 0) System.out.print(" tree-walk");
System.out.println();
}
}
/**
* set decay parameter
*/
private void doDecay(SimVector sv)
{
if (sv.parameters.length == 0)
{
if (theSim.tDecay == 0)
System.out.println("decay = No decay");
else
System.out.println("decay = " + Sim.deltaToNS(theSim.tDecay) + "ns");
} else
{
theSim.tDecay = Sim.nsToDelta(TextUtils.atof(sv.parameters[0]));
if (theSim.tDecay < 0)
theSim.tDecay = 0;
}
}
/**
* Set value of a node/vector to the requested value (hlux).
*/
private void doSetValue(SimVector sv)
{
if (sv.sigs == null) return;
for(Signal sig : sv.sigs)
{
Sim.Node n = nodeMap.get(sig);
setIn(n, commandName(sv.command).charAt(0));
}
}
/**
* display current inputs
*/
private void doInputs()
{
Sim.Node [] inpTbl = new Sim.Node[Sim.N_POTS];
inpTbl[Sim.HIGH] = inpTbl[Sim.LOW] = inpTbl[Sim.X] = null;
for(Sim.Node n : theSim.getNodeList())
{
if ((n.nFlags & (Sim.INPUT|Sim.ALIAS|Sim.POWER_RAIL|Sim.VISITED|Sim.INPUT_MASK)) == Sim.INPUT)
{
n.setNext(inpTbl[n.nPot]);
inpTbl[n.nPot] = n;
n.nFlags |= Sim.VISITED;
}
}
System.out.print("h inputs:");
for(Sim.Node n : hInputs)
{
System.out.print(" " + n.nName);
}
for(Sim.Node n = inpTbl[Sim.HIGH]; n != null; n.nFlags &= ~Sim.VISITED, n = n.getNext())
System.out.print(" " + n.nName);
System.out.println();
System.out.print("l inputs:");
for(Sim.Node n : lIinputs)
{
System.out.print(" " + n.nName);
}
for(Sim.Node n = inpTbl[Sim.LOW]; n != null; n.nFlags &= ~Sim.VISITED, n = n.getNext())
System.out.print(" " + n.nName);
System.out.println();
System.out.println("u inputs:");
for(Sim.Node n : uInputs)
{
System.out.println(" " + n.nName);
}
for(Sim.Node n = inpTbl[Sim.X]; n != null; n.nFlags &= ~Sim.VISITED, n = n.getNext())
System.out.println(" " + n.nName);
System.out.println();
}
private void doModel(SimVector sv)
{
if (sv.parameters.length < 1) return;
if (sv.parameters[0].equals("switch")) theSim.setModel(false); else
if (sv.parameters[0].equals("linear")) theSim.setModel(true); else
{
System.out.println("Unknown model: " + sv.parameters[0] + " (want either switch or linear)");
}
}
/**
* Do one simulation step
*/
private void doPhase()
{
stepPhase();
pnWatchList();
}
/**
* discover and print critical path for node's last transistion
*/
private void doPath(SimVector sv)
{
if (sv.sigs == null) return;
for(Signal sig : sv.sigs)
{
Sim.Node n = nodeMap.get(sig);
System.out.println("Critical path for last transition of " + n.nName + ":");
n = unAlias(n);
cPath(n, 0);
}
}
/**
* output message to console/log file
*/
private void doPrint(SimVector sv)
{
String infstr = "";
for(int n=0; n<sv.parameters.length; n++)
{
if (n != 1) infstr += " ";
infstr += sv.parameters[n];
}
System.out.println(infstr);
}
/**
* Print list of nodes with undefined (X) value
*/
private void doPrintX()
{
System.out.print("Nodes with undefined potential:");
column = 0;
for(Sim.Node n : theSim.getNodeList())
{
n = unAlias(n);
if ((n.nFlags & (Sim.MERGED | Sim.ALIAS)) == 0 && n.nPot == Sim.X)
{
int i = n.nName.length() + 2;
if (column + i >= MAXCOL)
{
column = 0;
}
column += i;
System.out.print(" " + n.nName);
}
}
System.out.println();
}
/**
* clock circuit through all the input vectors previously set up
*/
private void doRunSeq(SimVector sv)
{
// calculate how many clock cycles to run
int n = 1;
if (sv.parameters.length == 1)
{
n = TextUtils.atoi(sv.parameters[0]);
if (n <= 0) n = 1;
}
// run 'em by setting each input node to successive values of its associated sequence
if (sList.size() == 0)
{
System.out.println("no input vectors defined!");
return;
}
// determine the longest sequence
int maxSeq = 0;
for(Sequence cs : sList)
{
if (cs.values.length > maxSeq) maxSeq = cs.values.length;
}
// run it
for(int cycle = 0; cycle < n; cycle++)
{
for(int i = 0; i < maxSeq; i++)
{
vecValue(i);
if (clockIt(1)) return;
pnWatchList();
}
}
}
/**
* set tReport parameter
*/
private void doReport(SimVector sv)
{
if (sv.parameters[0].equalsIgnoreCase("decay")) theSim.tReport |= Sim.REPORT_DECAY; else
if (sv.parameters[0].equalsIgnoreCase("delay")) theSim.tReport |= Sim.REPORT_DELAY; else
if (sv.parameters[0].equalsIgnoreCase("tau")) theSim.tReport |= Sim.REPORT_TAU; else
if (sv.parameters[0].equalsIgnoreCase("tcoord")) theSim.tReport |= Sim.REPORT_TCOORD; else
if (sv.parameters[0].equalsIgnoreCase("none")) theSim.tReport = 0;
System.out.print("Report");
if (theSim.tReport == 0) System.out.println(" NONE"); else
{
if ((theSim.tReport&Sim.REPORT_DECAY) != 0) System.out.print(" decay");
if ((theSim.tReport&Sim.REPORT_DELAY) != 0) System.out.print(" delay");
if ((theSim.tReport&Sim.REPORT_TAU) != 0) System.out.print(" tau");
if ((theSim.tReport&Sim.DEBUG_TAUP) != 0) System.out.print(" tauP");
if ((theSim.tReport&Sim.REPORT_TCOORD) != 0) System.out.print(" tcoord");
System.out.println();
}
}
/**
* relax network, optionally set stepsize
*/
private void doStep(SimVector sv)
{
double newSize = sv.value;
long lNewSize = Sim.nsToDelta(newSize);
if (lNewSize <= 0) return;
relax(theSim.curDelta + lNewSize);
pnWatchList();
}
/**
* set bit vector
*/
private void doSet(SimVector sv)
{
DigitalSignal sig = findName(sv.parameters[0]);
if (sig == null)
{
System.out.println("Cannot find signal: " + sv.parameters[0]);
return;
}
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
if (sigsOnBus == null)
{
System.out.println("Signal: " + sv.parameters[0] + " is not a bus");
return;
}
if (sigsOnBus.size() != sv.parameters[1].length())
{
System.out.println("Wrong number of bits for this vector");
return;
}
for(int i = 0; i < sigsOnBus.size(); i++)
{
Sim.Node n = nodeMap.get(sigsOnBus.get(i));
setIn(n, sv.parameters[1].charAt(i));
}
}
private int tranCntNSD = 0, tranCntNG = 0;
/**
* Print event statistics.
*/
private void doStats(SimVector sv)
{
if (sv.parameters.length == 1)
{
if (tranCntNG == 0 && tranCntNSD == 0)
{
for(Sim.Node n : theSim.getNodeList())
{
if ((n.nFlags & (Sim.ALIAS | Sim.POWER_RAIL)) == 0)
{
tranCntNG += n.nGateList.size();
tranCntNSD += n.nTermList.size();
}
}
System.out.println("avg: # gates/node = " + TextUtils.formatDouble(tranCntNG / theSim.numNodes) +
", # src-drn/node = " + TextUtils.formatDouble(tranCntNSD / theSim.numNodes));
}
}
System.out.println("changes = " + theSim.numEdges);
System.out.println("punts (cns) = " + theSim.numPunted + " (" + theSim.numConsPunted + ")");
String n1 = "0.0";
String n2 = "0.0";
if (theSim.numPunted != 0)
{
n1 = TextUtils.formatDouble(100.0 / (theSim.numEdges / theSim.numPunted + 1.0));
n2 = TextUtils.formatDouble(theSim.numConsPunted * 100.0 / theSim.numPunted);
}
System.out.println("punts = " + n1 + "%, cons_punted = " + n2 + "%");
System.out.println("nevents = " + theSim.nEvent);
}
/**
* set stepsize
*/
private void doStepSize(SimVector sv)
{
if (sv.parameters.length < 1)
{
System.out.println("stepsize = " + Sim.deltaToNS(stepSize));
return;
}
double timeNS = TextUtils.atof(sv.parameters[0]);
long newSize = Sim.nsToDelta(timeNS);
if (newSize <= 0)
{
System.out.println("Bad step size: " + TextUtils.formatDouble(timeNS*1000) + "psec (must be 10 psec or larger)");
return;
}
stepSize = newSize;
}
/**
* mark nodes and vectors for stoping
*/
private void doStop(SimVector sv)
{
if (sv.sigs != null)
{
for(Signal sig : sv.sigs)
{
Sim.Node n = nodeMap.get(sig);
n = unAlias(n);
if ((n.nFlags & Sim.MERGED) != 0) continue;
if (true)
n.nFlags &= ~Sim.STOPONCHANGE;
else
n.nFlags |= Sim.STOPONCHANGE;
}
}
setVecNodes(Sim.WATCHVECTOR);
setVecNodes(Sim.STOPVECCHANGE);
}
/**
* mark nodes and vectors for tracing
*/
private void doTrace(SimVector sv)
{
if (sv.sigs != null)
{
for(Signal sig : sv.sigs)
{
Sim.Node n = nodeMap.get(sig);
n = unAlias(n);
if ((n.nFlags & Sim.MERGED) != 0)
{
System.out.println("can't trace " + n.nName);
continue;
}
n.nFlags |= Sim.WATCHED;
}
}
if (sv.sigsNegated != null)
{
for(Signal sig : sv.sigsNegated)
{
Sim.Node n = nodeMap.get(sig);
n = unAlias(n);
if ((n.nFlags & Sim.MERGED) != 0)
{
System.out.println("can't trace " + n.nName);
continue;
}
if ((n.nFlags & Sim.WATCHED) != 0)
{
System.out.println(n.nName + " was watched; not any more");
n.nFlags &= ~Sim.WATCHED;
}
}
}
setVecNodes(Sim.WATCHVECTOR);
}
/**
* Print list of transistors with src/drn shorted (or between power supplies).
*/
private void doTCap()
{
if (theSim.tCap.getSTrans() == theSim.tCap)
System.out.println("there are no shorted transistors");
else
System.out.println("shorted transistors:");
for(Sim.Trans t = theSim.tCap.getSTrans(); t != theSim.tCap; t = t.getSTrans())
{
System.out.println(" " + Sim.transistorType[Sim.baseType(t.tType)] + " g=" + ((Sim.Node)t.gate).nName + " s=" +
t.source.nName + " d=" + t.drain.nName + " (" +
(t.r.length / theSim.getConfig().lambdaCM) + "x" + (t.r.width / theSim.getConfig().lambdaCM) + ")");
}
}
/**
* set unitdelay parameter
*/
private void doUnitDelay(SimVector sv)
{
if (sv.parameters.length == 0)
{
if (theSim.tUnitDelay == 0)
System.out.println("unitdelay = OFF");
else
System.out.println("unitdelay = " + Sim.deltaToNS(theSim.tUnitDelay));
return;
}
theSim.tUnitDelay = (int)Sim.nsToDelta(TextUtils.atof(sv.parameters[0]));
if (theSim.tUnitDelay < 0) theSim.tUnitDelay = 0;
}
private void doUntil(SimVector sv)
{
String mask = null;
StringBuffer value = null;
int cCount = 0;
if (sv.parameters.length == 4)
{
mask = sv.parameters[1];
value = new StringBuffer(sv.parameters[2]);
cCount = TextUtils.atoi(sv.parameters[3]);
} else
{
mask = null;
value = new StringBuffer(sv.parameters[1]);
cCount = TextUtils.atoi(sv.parameters[2]);
}
DigitalSignal sig = findName(sv.parameters[0]);
if (sig == null)
{
System.out.println("UNTIL statement cannot find signal: " + sv.parameters[0]);
return;
}
String name = null;
int comp = 0;
int nBits = 1;
Sim.Node [] nodes = null;
if (sig.getBussedSignals() == null)
{
Sim.Node n = nodeMap.get(sig);
name = sig.getFullName();
n = unAlias(n);
Sim.Node [] nodeList = new Sim.Node[1];
nodeList[0] = n;
int cnt = 0;
while ((cnt <= cCount) && (comp = compareVector(nodeList, name, 1, mask, value.toString())) != 0)
{
cnt++;
clockIt(1);
}
nodes = new Sim.Node[1];
nodes[0] = n;
} else
{
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
Sim.Node [] nodeList = new Sim.Node[sigsOnBus.size()];
for(int i=0; i<sigsOnBus.size(); i++)
{
nodeList[i] = nodeMap.get(sigsOnBus.get(i));
}
int cnt = 0;
while ((cnt <= cCount) && (comp = compareVector(nodeList, sig.getFullName(), sigsOnBus.size(), mask, value.toString())) != 0)
{
cnt++;
clockIt(1);
}
name = sig.getFullName();
nBits = sigsOnBus.size();
nodes = nodeList;
}
if (comp != 0)
{
String infstr = "";
for(int i = 0; i < nBits; i++)
{
if (mask != null && mask.charAt(i) != '0')
{
infstr += "-";
value.setCharAt(i, '-');
}
else
infstr += Sim.vChars.charAt(nodes[i].nPot);
}
System.out.println("Assertion failed on '" + name + ": want (" + value + ") but got (" + infstr + ")");
}
}
private void doV(SimVector sv)
{
defSequence(sv.parameters, sList);
}
/************************** ASSERTION COMMANDS **************************/
/**
* assert a bit vector
*/
private void doAssert(SimVector sv)
{
String mask = null;
StringBuffer value = null;
if (sv.parameters.length == 3)
{
mask = sv.parameters[1];
value = new StringBuffer(sv.parameters[2]);
} else
{
value = new StringBuffer(sv.parameters[1]);
}
DigitalSignal sig = findName(sv.parameters[0]);
if (sig == null)
{
System.out.println("ASSERT statement cannot find signal: " + sv.parameters[0]);
return;
}
int comp = 0;
String name = null;
Sim.Node [] nodes = null;
if (sig.getBussedSignals() == null)
{
Sim.Node n = nodeMap.get(sig);
name = n.nName;
n = unAlias(n);
Sim.Node [] nodeList = new Sim.Node[1];
nodeList[0] = n;
comp = compareVector(nodeList, name, 1, mask, value.toString());
nodes = nodeList;
} else
{
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
Sim.Node [] nodeList = new Sim.Node[sigsOnBus.size()];
for(int i=0; i<sigsOnBus.size(); i++)
{
nodeList[i] = nodeMap.get(sigsOnBus.get(i));
}
comp = compareVector(nodeList, sig.getSignalName(), sigsOnBus.size(), mask, value.toString());
name = sig.getSignalName();
nodes = nodeList;
}
if (comp != 0)
{
String infstr = "";
for(int i = 0; i < nodes.length; i++)
{
if (mask != null && i < mask.length() && mask.charAt(i) != '0')
{
infstr += "-";
value.setCharAt(i, '-');
}
else
infstr += Sim.vChars.charAt(nodes[i].nPot);
}
System.out.println("Assertion failed on '" + name + "': want (" + value + ") but got (" + infstr + ")");
}
}
/** keeps current AssertWhen trigger */ private Sim.Node awTrig;
/** track pointer on the current AssertWhen list */ private AssertWhen awP;
private void doAssertWhen(SimVector sv)
{
DigitalSignal sig = findName(sv.parameters[0]);
if (sig == null)
{
System.out.println("ASSERTWHEN statement cannot find signal: " + sv.parameters[0]);
return;
}
if (sig.getBussedSignals() == null)
{
Sim.Node n = nodeMap.get(sig);
n = unAlias(n);
awTrig = n;
awTrig.awPot = (short)chToPot(sv.parameters[1].charAt(0));
Signal oSig = findName(sv.parameters[2]);
if (oSig == null)
{
System.out.println("ASSERTWHEN statement cannot find other signal: " + sv.parameters[2]);
return;
}
Sim.Node wN = nodeMap.get(oSig);
setupAssertWhen(wN, commandName(sv.command));
} else
{
System.out.println("trigger to assertWhen " + sv.parameters[0] + " can't be a vector");
}
}
private void setupAssertWhen(Sim.Node n, String val)
{
AssertWhen p = new AssertWhen();
p.node = n;
p.val = val.charAt(0);
p.nxt = null;
if (awTrig.awPending == null)
{
// first time
awTrig.awPending = p;
awP = p;
} else
{
// more than 1 matching nodes
awP.nxt = p;
awP = p;
}
}
/************************** IRSIM INTERFACE **************************/
public void evalAssertWhen(Sim.Node n)
{
for (AssertWhen p = n.awPending; p != null; )
{
String name = p.node.nName;
StringBuffer sb = new StringBuffer();
sb.append(p.val);
Sim.Node [] nodes = new Sim.Node[1];
nodes[0] = p.node;
int comp = compareVector(nodes, name, 1, null, sb.toString());
if (comp != 0)
System.out.println("Assertion failed on '" + name + "'");
p = p.nxt;
}
n.awPending = null;
}
/**
* Update the trace window so that endT is shown. If the update fits in the
* window, simply draw the missing parts. Otherwise scroll the traces,
* centered around endT.
*/
public void updateWindow(long endT)
{
long lastT = lastTime;
lastTime = endT;
if (endT <= endTime)
{
if (lastT >= startTime)
drawTraces(lastT, endT);
else if (endT > startTime)
drawTraces(startTime, endT);
} else // endT > endTime
{
if (lastT < endTime)
drawTraces(lastT, endTime);
}
}
/**
* Display traced vectors that just changed. There should be at least one.
*/
public void dispWatchVec(long which)
{
which &= (Sim.WATCHVECTOR | Sim.STOPVECCHANGE);
String temp = " @ " + Sim.deltaToNS(theSim.curDelta) + "ns ";
System.out.println(temp);
column = temp.length();
for(DigitalSignal sig : analysis.getBussedSignals())
{
Sim.Node b = nodeMap.get(sig);
if ((b.nFlags & which) == 0) continue;
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
boolean found = false;
for(DigitalSignal bSig : sigsOnBus)
{
Sim.Node bN = nodeMap.get(bSig);
if (bN.getTime() == theSim.curDelta)
{ found = true; break; }
}
if (found)
dVec(sig);
}
}
/************************** SUPPORT **************************/
private void initRSim()
{
xClock = new ArrayList<Sequence>();
maxClock = 0;
column = 0;
analyzerON = false;
firstVector = null;
for(int i = 0; i < 5; i++) listTbl[i] = null;
listTbl[Sim.inputNumber(Sim.H_INPUT)] = hInputs;
listTbl[Sim.inputNumber(Sim.L_INPUT)] = lIinputs;
listTbl[Sim.inputNumber(Sim.U_INPUT)] = uInputs;
listTbl[Sim.inputNumber(Sim.X_INPUT)] = xInputs;
}
/**
* Initialize the display times so that when first called the last time is
* shown on the screen. Default width is DEF_STEPS (simulation) steps.
*/
private void initTimes(long firstT, long stepSze, long lastT)
{
firstTime = firstT;
lastTime = lastT;
stepsTime = 4 * stepSze;
if (startTime <= firstTime)
{
if (lastT < stepsTime)
{
startTime = firstTime;
endTime = startTime + stepsTime;
// make it conform to the displayed range
Iterator<Panel> it = ww.getPanels();
if (it.hasNext())
{
Panel wp = it.next();
double max = wp.getMaxXAxis();
long endtime = Sim.nsToDelta(max * 1e9);
if (endtime > endTime) endTime = endtime;
}
double max = getEndTime();
long endT = Sim.nsToDelta(max * 1e9);
if (endT > endTime) endTime = endT;
} else
{
endTime = lastT + 2 * stepSze;
startTime = endTime - stepsTime;
if (startTime < firstTime)
{
stepSze = firstTime - startTime;
startTime += stepSze;
endTime += stepSze;
}
}
}
}
/**
* Get the resolution scale. As this number increases the min resolution
* descreases (becomes more accurate). A value of 1 corresponds to 1ns resolution.
* A value of 1000 corresponds to 1ps resolution.
* @return resolution scale factor
*/
protected static long getResolutionScale()
{
return resolutionScale;
}
/**
* Update the cache (begining of window and cursor) for traces that just
* became visible (or were just added).
*/
private void updateTraceCache()
{
long startT = startTime;
long cursT = firstTime;
for(Sim.Node nd : theSim.getNodeList())
{
Sim.HistEnt p = nd.wind;
Sim.HistEnt h = nd.cursor;
Sim.HistEnt nextH = h.getNextHist();
if (h.hTime > cursT || nextH.hTime <= cursT)
{
if (p.hTime <= cursT)
nd.cursor = p;
else
nd.cursor = nd.head;
}
if (startT <= p.hTime)
p = nd.head;
h = p.getNextHist();
while (h.hTime < startT)
{
p = h;
h = h.getNextHist();
}
nd.wind = p;
p = nd.cursor;
h = p.getNextHist();
while (h.hTime <= cursT)
{
p = h;
h = h.getNextHist();
}
nd.cursor = p;
}
}
/**
* Draw the traces horizontally from time1 to time2.
*/
private void drawTraces(long t1, long t2)
{
if (startTime != lastStart) // Update history cache
{
long startT = startTime;
boolean begin = (startT < lastStart);
for(Sim.Node nd : theSim.getNodeList())
{
Sim.HistEnt p = begin ? nd.head : nd.wind;
Sim.HistEnt h = p.getNextHist();
while (h.hTime < startT)
{
p = h;
h = h.getNextHist();
}
nd.wind = p;
}
lastStart = startTime;
}
for(Sim.Node nd : theSim.getNodeList())
{
if (nd.sig == null) continue;
if (t1 >= lastTime) continue;
Sim.HistEnt h = nd.wind;
if (h == null) continue;
int count = 0;
long curT = 0;
long endT = t2;
while (curT < endT)
{
int val = h.val;
while (h.hTime < endT && h.val == val)
h = h.getNextHist();
// advance time
long nextT;
if (h.hTime > endT)
{
nextT = endT;
} else
{
nextT = h.hTime;
}
// make sure there is room in the array
if (count >= traceTotal)
{
int newTotal = traceTotal * 2;
if (newTotal <= count) newTotal = count + 50;
double [] newTime = new double[newTotal];
short [] newState = new short[newTotal];
for(int i=0; i<count; i++)
{
newTime[i] = traceTime[i];
newState[i] = traceState[i];
}
traceTime = newTime;
traceState = newState;
traceTotal = newTotal;
}
//traceTime[count] = curT / 100000000000.0;
traceTime[count] = Sim.deltaToNS(curT) / 1000000000;
switch (val)
{
case Sim.LOW:
traceState[count] = Stimuli.LOGIC_LOW | Stimuli.GATE_STRENGTH;
break;
case Sim.HIGH:
traceState[count] = Stimuli.LOGIC_HIGH | Stimuli.GATE_STRENGTH;
break;
default:
traceState[count] = Stimuli.LOGIC_X | Stimuli.GATE_STRENGTH;
break;
}
curT = nextT;
count++;
}
double [] timeVector = new double[count];
int [] stateVector = new int[count];
for(int i=0; i<count; i++)
{
timeVector[i] = traceTime[i];
stateVector[i] = traceState[i];
}
nd.sig.setTimeVector(timeVector);
nd.sig.setStateVector(stateVector);
}
ww.repaint();
}
/**
* set/clear input status of node and add/remove it to/from corresponding list.
*/
private void setIn(Sim.Node n, char wChar)
{
while((n.nFlags & Sim.ALIAS) != 0)
n = n.nLink;
if ((n.nFlags & (Sim.POWER_RAIL | Sim.MERGED)) != 0) // Gnd, Vdd, or merged node
{
String pots = "lxuh";
if ((n.nFlags & Sim.MERGED) != 0 || pots.charAt(n.nPot) != wChar)
System.out.println("Can't drive `" + n.nName + "' to `" + wChar + "'");
} else
{
List list = listTbl[Sim.inputNumber((int)n.nFlags)];
switch (wChar)
{
case 'h': case '1':
if (list != null && list != hInputs)
{
n.nFlags = n.nFlags & ~Sim.INPUT_MASK;
list.remove(n);
}
if (! (list == hInputs || wasInP(n, Sim.HIGH)))
{
n.nFlags = (n.nFlags & ~Sim.INPUT_MASK) | Sim.H_INPUT;
hInputs.add(n);
}
break;
case 'l': case '0':
if (list != null && list != lIinputs)
{
n.nFlags = n.nFlags & ~Sim.INPUT_MASK;
list.remove(n);
}
if (! (list == lIinputs || wasInP(n, Sim.LOW)))
{
n.nFlags = (n.nFlags & ~Sim.INPUT_MASK) | Sim.L_INPUT;
lIinputs.add(n);
}
break;
case 'u':
if (list != null && list != uInputs)
{
n.nFlags = n.nFlags & ~Sim.INPUT_MASK;
list.remove(n);
}
if (! (list == uInputs || wasInP(n, Sim.X)))
{
n.nFlags = (n.nFlags & ~Sim.INPUT_MASK) | Sim.U_INPUT;
uInputs.add(n);
}
break;
case 'x':
if (list == xInputs)
break;
if (list != null)
{
n.nFlags = n.nFlags & ~Sim.INPUT_MASK;
list.remove(n);
}
if ((n.nFlags & Sim.INPUT) != 0)
{
n.nFlags = (n.nFlags & ~Sim.INPUT_MASK) | Sim.X_INPUT;
xInputs.add(n);
}
break;
default:
return;
}
}
}
private boolean wasInP(Sim.Node n, int p)
{
return (n.nFlags & Sim.INPUT) != 0 && n.nPot == p;
}
private String pValue(String node_name, Sim.Node node)
{
char pot = 0;
switch (node.nPot)
{
case 0: pot = '0'; break;
case 1: pot = 'X'; break;
case 2: pot = 'X'; break;
case 3: pot = '1'; break;
}
return node_name + "=" + pot + " ";
}
private String pGValue(Sim.Trans t)
{
String infstr = "";
if (theSim.irDebug != 0)
infstr += "[" + Sim.states[t.state] + "] ";
if ((t.tType & Sim.GATELIST) != 0)
{
infstr += "(";
for(t = (Sim.Trans) t.gate; t != null; t = t.getSTrans())
{
Sim.Node n = (Sim.Node)t.gate;
infstr += pValue(n.nName, n);
}
infstr += ") ";
} else
{
Sim.Node n = (Sim.Node)t.gate;
infstr += pValue(n.nName, n);
}
return infstr;
}
private String prOneRes(double r)
{
String ret = TextUtils.formatDouble(r);
if (r < 1e-9 || r > 100e9)
return ret;
int e = 3;
if (r >= 1000.0)
do { e++; r *= 0.001; } while(r >= 1000.0);
else if (r < 1 && r > 0)
do { e--; r *= 1000; } while(r < 1.0);
switch (e)
{
case 0: ret += "n"; break;
case 1: ret += "u"; break;
case 2: ret += "m"; break;
case 4: ret += "K"; break;
case 5: ret += "M"; break;
case 6: ret += "G"; break;
}
return ret;
}
private String prTRes(Sim.Resists r)
{
String v1 = prOneRes(r.rStatic);
String v2 = prOneRes(r.dynRes[Sim.R_HIGH]);
String v3 = prOneRes(r.dynRes[Sim.R_LOW]);
return "[" + v1 + ", " + v2 + ", " + v3 + "]";
}
private String pTrans(Sim.Trans t)
{
String infstr = Sim.transistorType[Sim.baseType(t.tType)] + " ";
if (Sim.baseType(t.tType) != Sim.RESIST)
infstr += pGValue(t);
infstr += pValue(t.source.nName, t.source);
infstr += pValue(t.drain.nName, t.drain);
infstr += prTRes(t.r);
if (t.tLink != t && (theSim.tReport & Sim.REPORT_TCOORD) != 0)
infstr += " <" + t.x + "," + t.y + ">";
return infstr;
}
/**
* compare pattern with string, case doesn't matter. "*" wildcard accepted
*/
private boolean strMatch(String pStr, String sStr)
{
int p = 0, s = 0;
for(;;)
{
if (getCh(pStr, p) == '*')
{
// skip past multiple wildcards
do
p++;
while(getCh(pStr, p) == '*');
// if pattern ends with wild card, automatic match
if (p >= pStr.length())
return true;
/* *p now points to first non-wildcard character, find matching
* character in string, then recursively match remaining pattern.
* if recursive match fails, assume current '*' matches more...
*/
while(s < sStr.length())
{
while(getCh(sStr, s) != getCh(pStr, p))
{
s++;
if (s >= sStr.length()) return false;
}
s++;
if (strMatch(pStr.substring(p+1), sStr.substring(s)))
return true;
}
// couldn't find matching character after '*', no match
return false;
}
else if (p >= pStr.length())
return s >= sStr.length();
else if (getCh(pStr, p++) != getCh(sStr, s++))
break;
}
return false;
}
private int getCh(String s, int index)
{
if (index >= s.length()) return 0;
return TextUtils.canonicChar(s.charAt(index));
}
/**
* map a character into one of the potentials that a node can be set/compared
*/
private int chToPot(char ch)
{
String s = "0ux1lUXhLUXH";
for(int i = 0; i < s.length(); i++)
if (s.charAt(i) == ch)
return i & (Sim.N_POTS - 1);
System.out.println(ch + ": unknown node value");
return Sim.N_POTS;
}
private Sim.Node unAlias(Sim.Node n)
{
while ((n.nFlags & Sim.ALIAS) != 0) n = n.nLink;
return n;
}
/**
* display node/vector values in display list
*/
private void pnWatchList()
{
theSim.getModel().printPendingEvents();
}
/**
* just in case node appears in more than one bit vector, run through all
* the vectors being traced and make sure the flag is set for each node.
*/
private void setVecNodes(int flag)
{
for(DigitalSignal sig : analysis.getBussedSignals())
{
Sim.Node b = nodeMap.get(sig);
if ((b.nFlags & flag) != 0)
{
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
for(Signal bSig : sigsOnBus)
{
Sim.Node bN = nodeMap.get(bSig);
bN.nFlags |= flag;
}
}
}
}
private int compareVector(Sim.Node [] np, String name, int nBits, String mask, String value)
{
if (value.length() != nBits)
{
System.out.println("wrong number of bits for value");
return 0;
}
if (mask != null && mask.length() != nBits)
{
System.out.println("wrong number of bits for mask");
return 0;
}
for(int i = 0; i < nBits; i++)
{
if (mask != null && mask.charAt(i) != '0') continue;
Sim.Node n = np[i];
int val = chToPot(value.charAt(i));
if (val >= Sim.N_POTS)
return 0;
if (val == Sim.X_X) val = Sim.X;
if (n.nPot != val)
return 1;
}
return 0;
}
private DigitalSignal findName(String name)
{
for(DigitalSignal sig : analysis.getSignals())
{
if (sig.getFullName().equals(name)) return sig;
}
return null;
}
/**
* display bit vector.
*/
private void dVec(DigitalSignal sig)
{
List<DigitalSignal> sigsOnBus = sig.getBussedSignals();
int i = sig.getSignalName().length() + 2 + sigsOnBus.size();
if (column + i >= MAXCOL)
{
column = 0;
}
column += i;
String bits = "";
for(Signal bSig : sigsOnBus)
{
Sim.Node n = nodeMap.get(bSig);
bits += Sim.vChars.charAt(n.nPot);
}
System.out.println(sig.getSignalName() + "=" + bits + " ");
}
/**
* Settle network until the specified stop time is reached.
* Premature returns (before stop time) indicate that a node/vector whose
* stop-bit set has just changed value.
*/
private long relax(long stopTime)
{
for(;;)
{
boolean repeat = theSim.getModel().step(stopTime);
if (!repeat) break;
}
return theSim.curDelta - stopTime;
}
/**
* set each node/vector in a clock sequence to its next value
*/
private void vecValue(int index)
{
for(Sequence cs : xClock)
{
String v = cs.values[index % cs.values.length];
if (cs.sig.getBussedSignals() == null)
{
Sim.Node n = nodeMap.get(cs.sig);
setIn(n, v.charAt(0));
} else
{
List<DigitalSignal> sigsOnBus = cs.sig.getBussedSignals();
for(int i=0; i<sigsOnBus.size(); i++)
{
Sim.Node n = nodeMap.get(sigsOnBus.get(i));
setIn(n, v.charAt(i));
}
}
}
}
/**
* process command line to yield a sequence structure. first arg is the
* name of the node/vector for which the sequence is to be defined, second
* and following args are the values.
*/
private void defSequence(String [] args, List<Sequence> list)
{
// if no arguments, get rid of all the sequences we have defined
if (args.length == 0)
{
list.clear();
return;
}
DigitalSignal sig = findName(args[0]);
if (sig == null)
{
System.out.println(args[0] + ": No such node or vector");
return;
}
int len = 1;
if (sig.getBussedSignals() != null)
len = sig.getBussedSignals().size();
Sim.Node n = nodeMap.get(sig);
if (sig.getBussedSignals() == null)
{
n = unAlias(n);
if ((n.nFlags & Sim.MERGED) != 0)
{
System.out.println(n.nName + " can't be part of a sequence");
return;
}
}
if (args.length == 1) // just destroy the given sequence
{
list.remove(sig);
return;
}
// make sure each value specification is the right length
for(int i = 1; i < args.length; i++)
if (args[i].length() != len)
{
System.out.println("value \"" + args[i] + "\" is not compatible with size of " + args[0] + " (" + len + ")");
return;
}
Sequence s = new Sequence();
s.values = new String[args.length-1];
s.sig = sig;
nodeMap.put(sig, n);
// process each value specification saving results in sequence
for(int i = 1; i < args.length; i++)
{
StringBuffer sb = new StringBuffer();
for(int p=0; p<args[i].length(); p++)
{
sb.append(potChars.charAt(chToPot(args[i].charAt(p))));
}
s.values[i-1] = sb.toString();
}
// all done! remove any old sequences for this node or vector.
list.remove(sig);
// insert result onto list
list.add(s);
// xClock.add(s);
}
private int whichPhase = 0;
/**
* Step each clock node through one simulation step
*/
private boolean stepPhase()
{
vecValue(whichPhase++);
if (relax(theSim.curDelta + stepSize) != 0) return true;
return false;
}
/**
* clock circuit specified number of times
*/
private boolean clockIt(int n)
{
int i = 0;
if (xClock.size() == 0)
{
System.out.println("no clock nodes defined!");
return false;
}
/* run 'em by setting each clock node to successive values of its
* associated sequence until all phases have been run.
*/
boolean interrupted = false;
for(int cycle = 0; cycle < n; cycle++)
{
for(i = 0; i < maxClock; i += 1)
{
if (stepPhase())
{
interrupted = true;
break;
}
}
if (interrupted) break;
}
// finally display results if requested to do so
pnWatchList();
return interrupted;
}
static long pTime;
/**
* print traceback of node's activity and that of its ancestors
*/
private void cPath(Sim.Node n, int level)
{
// no last transition!
if ((n.nFlags & Sim.MERGED) != 0 || n.getCause() == null)
{
System.out.println(" there is no previous transition!");
}
/* here if we come across a node which has changed more recently than
* the time reached during the backtrace. We can't continue the
* backtrace in any reasonable fashion, so we stop here.
*/
else if (level != 0 && n.getTime() > pTime)
{
System.out.println(" transition of " + n.nName + ", which has since changed again");
}
/* here if there seems to be a cause for this node's transition.
* If the node appears to have 'caused' its own transition (n.t.cause
* == n), that means it was input. Otherwise continue backtrace...
*/
else if (n.getCause() == n)
{
System.out.println(" " + n.nName + " . " + Sim.vChars.charAt(n.nPot) +
" @ " + Sim.deltaToNS(n.getTime()) + "ns , node was an input");
}
else if ((n.getCause().nFlags & Sim.VISITED) != 0)
{
System.out.println(" ... loop in traceback");
}
else
{
long deltaT = n.getTime() - n.getCause().getTime();
n.nFlags |= Sim.VISITED;
pTime = n.getTime();
cPath(n.getCause(), level + 1);
n.nFlags &= ~Sim.VISITED;
if (deltaT < 0)
System.out.println(" " + n.nName + " . " + Sim.vChars.charAt(n.nPot) +
" @ " + Sim.deltaToNS(n.getTime()) + "ns (??)");
else
System.out.println(" " + n.nName + " . " + Sim.vChars.charAt(n.nPot) +
" @ " + Sim.deltaToNS(n.getTime()) + "ns (" + Sim.deltaToNS(deltaT) + "ns)");
}
}
private void clearInputs()
{
for(int i = 0; i < 5; i++)
{
if (listTbl[i] == null) continue;
for(Sim.Node n : (List<Sim.Node>)listTbl[i])
{
if ((n.nFlags & Sim.POWER_RAIL) == 0)
n.nFlags &= ~(Sim.INPUT_MASK | Sim.INPUT);
}
listTbl[i].clear();
}
for(Sim.Node n : theSim.getNodeList() )
{
if ((n.nFlags & Sim.POWER_RAIL) == 0)
n.nFlags &= ~Sim.INPUT;
}
}
}