All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.plugins.irsim.Analyzer Maven / Gradle / Ivy

/* -*- 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.api.irsim.IAnalyzer;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 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 implements IAnalyzer.EngineIRSIM, SimAPI.Analyzer
{
	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;
	/** 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.";
	/** 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 sigs;
		/** negated signals named in command */		List sigsNegated;
		/** duration of step, where appropriate */	double        value;
		/** next in list of vectors */				SimVector     next;
	}

	public class AssertWhen implements Runnable
	{
		/** which node we will check */				SimAPI.Node       node;
		/** what value has the node */				char	       val;
		/** next in list of assertions */			AssertWhen     nxt;
        
        public void run() {
            evalAssertWhen(node);
        }
	}

	private static class Sequence
	{
		/** signal to control */					IAnalyzer.GuiSignal  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 IAnalyzer.LogicState [] traceState;
	private int       traceTotal = 0;

	/** vectors which make up clock */				private List xClock;
	/** vectors which make up a sequence */			private List 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   hInputs = new ArrayList();
	/** list of nodes to be driven low */			public List   lIinputs = new ArrayList();
	/** list of nodes to be driven X */				public List   uInputs = new ArrayList();
	/** list of nodes to be removed from input */	public List   xInputs = new ArrayList();

	/** set when analyzer is running */				public boolean          analyzerON;
    /** irDebug preferneces */                      public int              irDebug;
    /** show IRSIM commands */                      public boolean          showCommands;

	/** the simulation engine */					private final SimAPI    theSim;
    /** the GUI interface */                        private final IAnalyzer.GUI gui;
	/** mapping from signals to nodes */			private HashMap nodeMap;
	/** mapping from nodes to signals */			private HashMap signalMap = new HashMap();

	/************************** ELECTRIC INTERFACE **************************/

	Analyzer(IAnalyzer.GUI gui, SimAPI sim, int irDebug, boolean showCommands)
	{
        this.gui = gui;
        this.irDebug = irDebug;
        this.showCommands = showCommands;
		theSim = sim;
        theSim.setDebug(irDebug);
        theSim.setAnalyzer(this);
	}
 
    /**
     * Put triansitor into the circuit
     * @param gateName name of transistor gate network
     * @param sourceName name of transistor gate network
     * @param drainName drain name of transistor gate network
     * @param gateLength gate length (lambda)
     * @param gateWidth gate width (lambda)
     * @param activeArea active area (lambda^2)
     * @param activePerim active perim (lambda^2)
     * @param centerX x-coordinate of center (lambda)
     * @param centerY y coordinate of cneter (lambda)
     * @param isNTypeTransistor true if this is N-type transistor
     */
    public void putTransistor(String gateName, String sourceName, String drainName,
            double gateLength, double gateWidth,
            double activeArea, double activePerim,
            double centerX, double centerY,
            boolean isNTypeTransistor) {
        theSim.putTransistor(gateName, sourceName, drainName, gateLength, gateWidth, activeArea, activePerim, centerX, centerY, isNTypeTransistor);
    }
    
    /**
     * Put resistor into the circuit
     * @param net1 name of first terminal network
     * @param net2 name of second terminal network
     * @param resistance resistance (ohm)
     */
    public void putResistor(String net1, String net2, double resistance) {
        theSim.putResistor(net1, net2, resistance);
    }

    /**
     * Put capacitor into the circuit
     * @param net1 name of first terminal network
     * @param net2 name of second terminal network
     * @param capacitance capacitance (pf)
     */
    public void putCapacitor(String net1, String net2, double capacitance) {
        theSim.putCapacitor(net1, net2, capacitance);
    }

	/**
	 * Load a .sim file into memory.
	 *
	 * A .sim file consists of a series of lines, each of which begins with a key letter.
	 * The key letter beginning a line determines how the remainder of the line is interpreted.
	 * The following are the list of key letters understood.
	 *
	 *   | units: s tech: tech format: MIT|LBL|SU
	 *     If present, this must be the first line in the .sim file.
	 *     It identifies the technology of this circuit as tech and gives a scale factor for units of linear dimension as s.
	 *     All linear dimensions appearing in the .sim file are multiplied by s to give centimicrons.
	 *     The format field signifies the sim variant. Electric only recognizes SU format. 
	 *   type g s d l w x y g=gattrs s=sattrs d=dattrs
	 *     Defines a transistor of type type. Currently, type may be e or d for NMOS, or p or n for CMOS.
	 *     The name of the node to which the gate, source, and drain of the transistor are connected are given by g, s, and d respectively.
	 *     The length and width of the transistor are l and w. The next two tokens, x and y, are optional.
	 *     If present, they give the location of a point inside the gate region of the transistor.
	 *     The last three tokens are the attribute lists for the transistor gate, source, and drain.
	 *     If no attributes are present for a particular terminal, the corresponding attribute list may be absent
	 *     (i.e, there may be no g= field at all).
	 *     The attribute lists gattrs, etc. are comma-separated lists of labels.
	 *     The label names should not include any spaces, although some tools can accept label names with
	 *     spaces if they are enclosed in double quotes. In version 6.4.5 and later the default format
	 *     produced by ext2sim is SU. In this format the attribute of the gate starting with S_ is the substrate node of the fet.
	 *     The attributes of the gate, and source and substrate starting with A_, P_ are the area and perimeter
	 *     (summed for that node only once) of the source and drain respectively. This addition to the format is backwards compatible. 
	 *   C n1 n2 cap
	 *     Defines a capacitor between nodes n1 and n2. The value of the capacitor is cap femtofarads.
	 *     NOTE: since many analysis tools compute transistor gate capacitance themselves from the
	 *     transistor's area and perimeter, the capacitance between a node and substrate (GND!)
	 *     normally does not include the capacitance from transistor gates connected to that node.
	 *     If the .sim file was produced by ext2sim(1), check the technology file that was used to
	 *     produce the original .ext files to see whether transistor gate capacitance is included or excluded;
	 *     see "Magic Maintainer's Manual 2 - The Technology File for details. 
	 *   R node res
	 *     Defines the lumped resistance of node node to be res ohms.
	 *   r node1 node2 res
	 *     Defines an explicit resistor between nodes node1 and node2 of resistance res ohms.
	 *   N node darea dperim parea pperim marea mperim
	 *     As an alternative to computed capacitances, some tools expect the total perimeter and area
	 *     of the polysilicon, diffusion, and metal in each node to be reported in the .sim file.
	 *     The N construct associates diffusion area darea (in square centimicrons) and diffusion
	 *     perimeter dperim (in centimicrons) with node node, polysilicon area parea and perimeter pperim,
	 *     and metal area marea and perimeter mperim. This construct is technology dependent and obsolete. 
	 *   = node1 node2
	 *     Each node in a .sim file is named implicitly by having it appear in a transistor definition.
	 *     All node names appearing in a .sim file are assumed to be distinct.
	 *     Some tools, such as esim(1), recognize aliases for node names.
	 *     The = construct allows the name node2 to be defined as an alias for the name node1.
	 *     Aliases defined by means of this construct may not appear anywhere else in the .sim file.
     * @param simReader Reader of .sim file
     * @param fileName file name for error messages
     * @return number of errors
     */
    public int inputSim(Reader simReader, String fileName) throws IOException {
        return theSim.inputSim(simReader, fileName);
    }

    /**
     * Finish initialization of the circuit.
     */
    public void finishNetwork() {
        theSim.finishNetwork();
    }
    
    /**
     * Get lambda value in nanometers
     * @return lambda in nanometers
     */
    public double getLambda() {
        return theSim.getLambda();
    }
    
    /**
     * Finish initialization
     */
	public void init()
	{
		// tell the simulator to watch all signals
		initTimes(0, 50000, theSim.getCurDelta());

		for(SimAPI.Node n : theSim.getNodes())
		{
			while (n.getFlags(SimAPI.ALIAS) != 0)
				n = n.getLink();

			if (n.getFlags(SimAPI.MERGED) != 0)
				System.out.println("can't watch node " + n.getName());
            n.setCursor(n.getHead());
			n.setWind(n.getHead());
		}
		updateWindow(0);
		lastStart = theSim.getMaxTime();
		analyzerON = true;

		// read signal values
		updateWindow(theSim.getCurDelta());
	}

    /**
     * Finish initialization of the circuit and convert Stimuli.
     */
    public void convertStimuli() 
    {
		nodeMap = new HashMap();
		List sigList = new ArrayList();
		for(SimAPI.Node n : theSim.getNodes())
		{
			if (n.getName().equalsIgnoreCase("vdd") || n.getName().equalsIgnoreCase("gnd")) continue;

			// make a signal for it
			IAnalyzer.GuiSignal sig = gui.makeSignal(n.getName());
            signalMap.put(n, sig);
//			n.sig = sig;
			sigList.add(sig);
			nodeMap.put(sig, n);

            sig.addSample(0, IAnalyzer.LogicState.LOGIC_0);
            sig.addSample(0.00000001, IAnalyzer.LogicState.LOGIC_0);
		}

		// make bus signals from individual ones found in the list
		gui.makeBusSignals(sigList);
	}

    public void newContolPoint(String signalName, double insertTime, IAnalyzer.LogicState value) {
        int command;
        switch (value) {
            case LOGIC_1:
                command = VECTORH;
                break;
            case LOGIC_0:
                command = VECTORL;
                break;
            default:
                command = VECTORX;
        }
        newVector(command, new String[] {signalName}, insertTime, false);
    }
    
    /**
     * Method to show information about the currently-selected signal.
     */
    public void showSignalInfo(IAnalyzer.GuiSignal sig) {
        SimVector excl = new SimVector();
        excl.command = VECTOREXCL;
        excl.sigs = new ArrayList();
        excl.sigs.add(sig);
        issueCommand(excl);

        excl.command = VECTORQUESTION;
        issueCommand(excl);
    }
    
	/**
	 * Method to remove all stimuli from the currently-selected signal.
     * @param sig currently selected signal.
	 */
    public void clearControlPoints(IAnalyzer.GuiSignal sig) {
		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;
    }
    
//	/**
//	 * Method to reload the circuit data.
//	 */
//	public void refresh(IRSIMPreferences ip)
//	{
//		// make a new simulation object
//		theSim = new Sim(this);
//
//		// now initialize the simulator
//		initRSim();
//
//		// Load network
//		loadCircuit(ip);
//		WaveformWindow.refreshSimulationData(sd, ww);
//
//		if (vectorFileName != null) loadVectorFile();
//		init();
//
//		playVectors();
//	}

	/************************** SIMULATION VECTORS **************************/

	/**
	 * Method to play the simulation vectors into the simulator.
	 */
	public 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 = deltaToNS(stepSize);
		issueCommand(step);
		analyzerON = true;
		updateWindow(theSim.getCurDelta());

		// update main cursor location if requested
        gui.setMainXPositionCursor(curTime);
	}

	/**
	 * Method to clear all simulation vectors.
	 */
	public void clearAllVectors()
	{
		firstVector = null;
		lastVector = null;
	}

	/**
	 * Method to restore the current stimuli information from URL.
     * @param reader Reader with stimuli information
	 */
	public void restoreStimuli(Reader reader) throws IOException
	{
		LineNumberReader lineReader = new LineNumberReader(reader);
        // remove all vectors
        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 = theSim.parseLine(buf);
            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 sigs = new ArrayList();
                getTargetNodes(targ, 1, sigs, null);
                gui.openPanel(sigs);
                continue;
            }

            // handle aggregation of signals into busses
            if (command == VECTORVECTOR)
            {
                // find this vector name in the list of vectors
//					Signal busSig = null;
//					if (busSig == null)
//						busSig = DigitalSample.createSignal(sigCollection, sd, targ[1], null);
                List sigs = new ArrayList();
                getTargetNodes(targ, 2, sigs, null);
                IAnalyzer.GuiSignal[] subsigs = new IAnalyzer.GuiSignal[sigs.size()];
                for(int i=0; i " + commandName(sv.command));
			if (sv.parameters != null)
			{
				for(int i=0; i 0)
				{
					newSize = atof(params[0]);
					long lNewSize = nsToDelta(newSize);
					if (lNewSize <= 0)
					{
						System.out.println("Bad step size: " + formatDouble(newSize*1000) + "psec (must be 10 psec or larger), ignoring");
						return null;
					}
				}
				newsv.value = newSize;
				break;
			case VECTORSTEPSIZE:
				if (params.length > 0)
					stepSize = nsToDelta(atof(params[0]));
				break;

			case VECTORBACK:
				newsv.value = 0;
				if (params.length > 0)
				{
					newsv.value = 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();
				newsv.sigsNegated = null;
				if (command == VECTORT) newsv.sigsNegated = new ArrayList();
				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(IAnalyzer.GuiSignal 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 = nsToDelta(((curTime + stepSze) - insertTime) / cmdFileUnits);
						if (ss != 0 && Electric.doublesLessThan(insertTime, curTime+stepSze))
						{
							// splitting step at "insertTime"
							sv.parameters = new String[1];
							sv.value = (insertTime-curTime) / cmdFileUnits;
							sv.parameters[0] = 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] = formatDouble(afterSV.value);
							afterSV.next = sv.next;
							sv.next = afterSV;
						}
						curTime += stepSze;
						break;
					case VECTORSTEPSIZE:
						if (sv.parameters.length > 0)
							defaultStepSize = 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 = atoi(sv.parameters[0]);
						curTime += defaultStepSize * clockPhases * mult;
						break;
					case VECTORP:
						curTime += defaultStepSize;
						break;
				}
				lastSV = sv;
				if (!Electric.doublesLessThan(curTime, insertTime)) break;
			}
			if (Electric.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] = formatDouble(thisStep);
//					afterSV.parameters[0] = Electric.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;
    }

	/**
	 * Method to remove the selected stimuli.
	 * @return true if stimuli were deleted.
	 */
	public boolean clearControlPoint(IAnalyzer.GuiSignal 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 = 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 = atoi(sv.parameters[0]);
					curTime += defaultStepSize * clockPhases * mult;
					break;
				case VECTORP:
					curTime += defaultStepSize;
					break;
				case VECTORL:
				case VECTORH:
				case VECTORX:
					if (Electric.doublesEqual(insertTime, curTime))
					{
						boolean found = false;
						for(IAnalyzer.GuiSignal 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 (Electric.doublesLessThan(insertTime, curTime)) break;
		}
		return cleared;
	}

	private void getTargetNodes(String [] params, int low, List normalList, List negatedList)
	{
		int size = params.length - low;
		for(int i=0; i= 0)
			{
				for(IAnalyzer.GuiSignal sig : gui.getSignals())
				{
					if (strMatch(name, sig.getFullName()))
					{
						if (negated) negatedList.add(sig); else
							normalList.add(sig);
					}
				}
			} else
			{
				// no wildcards: just find the name
				IAnalyzer.GuiSignal 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 = 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 = 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(IAnalyzer.GuiSignal sig : sv.sigs)
		{
			SimAPI.Node n = nodeMap.get(sig);
			if (n == null) continue;

			String name = n.getName();
			while(n.getFlags(SimAPI.ALIAS) != 0)
				n = n.getLink();

			if (n.getFlags(SimAPI.MERGED) != 0)
			{
				System.out.println(name + " => node is inside a transistor stack");
				return;
			}

			String infstr = "";
			infstr += pValue(name, n);
            infstr += n.describeDelay();
			System.out.println();

			infstr = "";
			if (sv.command == VECTOREXCL)
			{
				infstr += "is computed from:";
				for(SimAPI.Trans t : n.getTerms())
				{
					infstr += "  ";
					if (irDebug == 0)
					{
						String drive = null;
						SimAPI.Node rail = t.getDrain().getFlags(SimAPI.POWER_RAIL) != 0 ? t.getDrain() : t.getSource();
						if (t.getBaseType() == SimAPI.NCHAN && rail == theSim.getGroundNode())
							drive = "pulled down by ";
						else if (t.getBaseType() == SimAPI.PCHAN && rail == theSim.getPowerNode())
							drive = "pulled up by ";
						else if (t.getBaseType() == SimAPI.DEP && rail == theSim.getPowerNode() &&
							t.getOtherNode(rail) == t.getGate())
								drive = "pullup ";
						else
							infstr += pTrans(t);

						if (drive != null)
						{
							infstr += drive;
							infstr += pGValue(t);
							infstr += prTRes(t);
							if (t.getLink() != t && (theSim.getReport() & SimAPI.REPORT_TCOORD) != 0)
								infstr += " <" + t.getX() + "," + t.getY() + ">";
						}
					} else
					{
						infstr += pTrans(t);
					}
				}
			} else
			{
				infstr += "affects:";
				for(SimAPI.Trans t : n.getGates())
				{
					infstr += pTrans(t);
				}
			}
			System.out.println(infstr);

            String[] pendingEvents = n.describePendingEvents();
			if (pendingEvents != null)
			{
				System.out.println("Pending events:");
				for(String s: pendingEvents)
					System.out.println(s);
			}
		}
	}

	/**
	 * print histogram of circuit activity in specified time interval
	 */
	private void doActivity(SimVector sv)
	{
		long begin = nsToDelta(atof(sv.parameters[0]));
		long end = theSim.getCurDelta();
		if (sv.parameters.length > 1)
			end = nsToDelta(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(SimAPI.Node n : theSim.getNodes())
		{
			if (n.getFlags(SimAPI.ALIAS | SimAPI.MERGED | SimAPI.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: " + deltaToNS(begin) +
			" . " + deltaToNS(end) + "ns (bucket size = " + deltaToNS(size) + ")");

		for(int i = 0; i < NBUCKETS; i += 1)
			System.out.println(" " + deltaToNS(begin + (i * size)) + " -" + deltaToNS(begin + (i + 1) * size) + table[i]);
	}

	/**
	 * Print nodes that are aliases
	 */
	private void doPrintAlias()
	{
		if (theSim.getNumAliases() == 0)
			System.out.println("there are no aliases");
		else
		{
			System.out.println("there are " + theSim.getNumAliases() + " aliases:");
			for(SimAPI.Node n : theSim.getNodes())
			{
				if (n.getFlags(SimAPI.ALIAS) != 0)
				{
					n = unAlias(n);
					String is_merge = n.getFlags(SimAPI.MERGED) != 0 ? " (part of a stack)" : "";
					System.out.println("  " + n.getName() + " . " + n.getName() + is_merge);
				}
			}
		}
	}

	/**
	 * Move back simulation time to specified time.
	 */
	private void doBack(SimVector sv)
	{
		long newT = nsToDelta(sv.value);
		if (newT < 0 || newT > theSim.getCurDelta())
		{
			System.out.println(sv.value + ": invalid time in BACK command");
			return;
		}

		theSim.setCurDelta(newT);
		clearInputs();
		theSim.backSimTime(theSim.getCurDelta(), 0);
		theSim.clearCurNode();			// fudge
		for(SimAPI.Node n : theSim.getNodes())
		{
			theSim.backToTime(n);
		}
		if (theSim.getCurDelta() == 0)
			theSim.reInit();

		if (analyzerON)
		{
			for(SimAPI.Node n : theSim.getNodes())
			{
                n.setCursor(n.getHead());
				n.setWind(n.getHead());
			}

			// should set "theSim.curDelta" to the width of the screen
			initTimes(0, stepsTime / DEF_STEPS, theSim.getCurDelta());
			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 = 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 = nsToDelta(atof(sv.parameters[0]));
		long end = theSim.getCurDelta();
		if (sv.parameters.length > 1)
			end = nsToDelta(atof(sv.parameters[1]));

		column = 0;
		System.out.print("Nodes with last transition in interval " + deltaToNS(begin) + " . " + deltaToNS(end) + "ns:");

		for(SimAPI.Node n : theSim.getNodes())
		{
			n = unAlias(n);

			if (n.getFlags(SimAPI.MERGED | SimAPI.ALIAS) != 0) return;

			if (n.getTime() >= begin && n.getTime() <= end)
			{
				int i = n.getName().length() + 2;
				if (column + i >= MAXCOL)
				{
					column = 0;
				}
				column += i;
				System.out.print("  " + n.getName());
			}
		}
		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) irDebug = 0; else
		{
			for(int i=0; i= MAXCOL)
				{
					column = 0;
				}
				column += i;
				System.out.print("  " + n.getName());
			}
		}
		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 = 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.setReport(SimAPI.REPORT_DECAY); else
			if (sv.parameters[0].equalsIgnoreCase("delay")) theSim.setReport(SimAPI.REPORT_DELAY); else
				if (sv.parameters[0].equalsIgnoreCase("tau")) theSim.setReport(SimAPI.REPORT_TAU); else
					if (sv.parameters[0].equalsIgnoreCase("tcoord")) theSim.setReport(SimAPI.REPORT_TCOORD); else
						if (sv.parameters[0].equalsIgnoreCase("none")) theSim.clearReport();
		System.out.print("Report");
		if (theSim.getReport() == 0) System.out.println(" NONE"); else
		{
			if ((theSim.getReport()&SimAPI.REPORT_DECAY) != 0) System.out.print(" decay");
			if ((theSim.getReport()&SimAPI.REPORT_DELAY) != 0) System.out.print(" delay");
			if ((theSim.getReport()&SimAPI.REPORT_TAU) != 0) System.out.print(" tau");
			if ((theSim.getReport()&SimAPI.DEBUG_TAUP) != 0) System.out.print(" tauP");
			if ((theSim.getReport()&SimAPI.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 = nsToDelta(newSize);
		if (lNewSize <= 0) return;
		relax(theSim.getCurDelta() + lNewSize);
		pnWatchList();
	}

	/**
	 * set bit vector
	 */
	private void doSet(SimVector sv)
	{
		IAnalyzer.GuiSignal sig = findName(sv.parameters[0]);
		if (sig == null)
		{
			System.out.println("Cannot find signal: " + sv.parameters[0]);
			return;
		}

		IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
		if (sigsOnBus == null)
		{
			System.out.println("Signal: " + sv.parameters[0] + " is not a bus");
			return;
		}
		if (sigsOnBus.length != sv.parameters[1].length())
		{
			System.out.println("Wrong number of bits for this vector");
			return;
		}
		for(int i = 0; i < sigsOnBus.length; i++)
		{
			SimAPI.Node n = nodeMap.get(sigsOnBus[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(SimAPI.Node n : theSim.getNodes())
				{
					if (n.getFlags(SimAPI.ALIAS | SimAPI.POWER_RAIL) == 0)
					{
						tranCntNG += n.getGates().size();
						tranCntNSD += n.getTerms().size();
					}
				}
				System.out.println("avg: # gates/node = " + formatDouble(tranCntNG / theSim.getNumNodes()) +
					",  # src-drn/node = " + formatDouble(tranCntNSD / theSim.getNumNodes()));
			}
		}
		System.out.println("changes = " + theSim.getNumEdges());
		System.out.println("punts (cns) = " + theSim.getNumPunted() + " (" + theSim.getNumConsPunted() + ")");
		String n1 = "0.0";
		String n2 = "0.0";
		if (theSim.getNumPunted() != 0)
		{
			n1 = formatDouble(100.0 / (theSim.getNumEdges() / theSim.getNumPunted() + 1.0));
			n2 = formatDouble(theSim.getNumConsPunted() * 100.0 / theSim.getNumPunted());
		}
		System.out.println("punts = " + n1 + "%, cons_punted = " + n2 + "%");

		System.out.println("nevents = " + theSim.getNumEvents());
	}

	/**
	 * set stepsize
	 */
	private void doStepSize(SimVector sv)
	{
		if (sv.parameters.length < 1)
		{
			System.out.println("stepsize = " + deltaToNS(stepSize));
			return;
		}

		double timeNS = atof(sv.parameters[0]);
		long newSize = nsToDelta(timeNS);
		if (newSize <= 0)
		{
			System.out.println("Bad step size: " + formatDouble(timeNS*1000) + "psec (must be 10 psec or larger)");
			return;
		}
		stepSize = newSize;
	}

	/**
	 * mark nodes and vectors for stopping
	 */
	private void doStop(SimVector sv)
	{
		if (sv.sigs != null)
		{
			for(IAnalyzer.GuiSignal sig : sv.sigs)
			{
				SimAPI.Node n = nodeMap.get(sig);
				n = unAlias(n);
				if (n.getFlags(SimAPI.MERGED) != 0) continue;

				if (true)
					n.clearFlags(SimAPI.STOPONCHANGE);
				else
					n.setFlags(SimAPI.STOPONCHANGE);
			}
		}
		setVecNodes(SimAPI.WATCHVECTOR);
		setVecNodes(SimAPI.STOPVECCHANGE);
	}

	/**
	 * mark nodes and vectors for tracing
	 */
	private void doTrace(SimVector sv)
	{
		if (sv.sigs != null)
		{
			for(IAnalyzer.GuiSignal sig : sv.sigs)
			{
				SimAPI.Node n = nodeMap.get(sig);
				n = unAlias(n);

				if (n.getFlags(SimAPI.MERGED) != 0)
				{
					System.out.println("can't trace " + n.getName());
					continue;
				}

				n.setFlags(SimAPI.WATCHED);
			}
		}
		if (sv.sigsNegated != null)
		{
			for(IAnalyzer.GuiSignal sig : sv.sigsNegated)
			{
				SimAPI.Node n = nodeMap.get(sig);
				n = unAlias(n);

				if (n.getFlags(SimAPI.MERGED) != 0)
				{
					System.out.println("can't trace " + n.getName());
					continue;
				}

				if (n.getFlags(SimAPI.WATCHED) != 0)
				{
					System.out.println(n.getName() + " was watched; not any more");
					n.clearFlags(SimAPI.WATCHED);
				}

			}
		}
		setVecNodes(SimAPI.WATCHVECTOR);
	}

	/**
	 * Print list of transistors with src/drn shorted (or between power supplies).
	 */
	private void doTCap()
	{
        Collection shortedTransistors = theSim.getShortedTransistors();
		if (shortedTransistors.isEmpty())
			System.out.println("there are no shorted transistors");
		else
			System.out.println("shorted transistors:");
		for(SimAPI.Trans t: shortedTransistors)
		{
			System.out.println(" " + t.describeBaseType() + " g=" + t.getGate().getName() + " s=" +
				t.getSource().getName() + " d=" + t.getDrain().getName() + " (" +
				(t.getLength() / theSim.getLambdaCM()) + "x" + (t.getWidth() / theSim.getLambdaCM()) + ")");
		}
	}

	/**
	 * set unitdelay parameter
	 */
	private void doUnitDelay(SimVector sv)
	{
		if (sv.parameters.length == 0)
		{
			if (theSim.getUnitDelay() == 0)
				System.out.println("unitdelay = OFF");
			else
				System.out.println("unitdelay = " + deltaToNS(theSim.getUnitDelay()));
			return;
		}

		theSim.setUnitDelay((int)nsToDelta(atof(sv.parameters[0])));
		if (theSim.getUnitDelay() < 0) theSim.setUnitDelay(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 = atoi(sv.parameters[3]);
		} else
		{
			mask = null;
			value = new StringBuffer(sv.parameters[1]);
			cCount = atoi(sv.parameters[2]);
		}

		IAnalyzer.GuiSignal 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;
		SimAPI.Node [] nodes = null;
		IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
		if (sigsOnBus == null)
		{
			SimAPI.Node n = nodeMap.get(sig);
			name = sig.getFullName();
			n = unAlias(n);
			SimAPI.Node [] nodeList = new SimAPI.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 SimAPI.Node[1];
			nodes[0] = n;
		} else
		{
			SimAPI.Node [] nodeList = new SimAPI.Node[sigsOnBus.length];
			for(int i=0; i= 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 &= (SimAPI.WATCHVECTOR | SimAPI.STOPVECCHANGE);
		String temp = " @ " + deltaToNS(theSim.getCurDelta()) + "ns ";
		System.out.println(temp);
		column = temp.length();
		Collection sigs = gui.getSignals();
		for(IAnalyzer.GuiSignal sig : sigs)
		{
			IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
			if (sigsOnBus == null) continue;
			SimAPI.Node b = nodeMap.get(sig);
			if (b.getFlags(which) == 0) continue;
			boolean found = false;
			for(IAnalyzer.GuiSignal bSig : sigsOnBus)
			{
				SimAPI.Node bN = nodeMap.get(bSig);
				if (bN.getTime() == theSim.getCurDelta())
					{ found = true;   break; }
			}
			if (found)
				dVec(sig);
		}
	}

	/************************** SUPPORT **************************/

	void initRSim()
	{
		xClock = new ArrayList();
		maxClock = 0;
		column = 0;
		analyzerON = false;
		firstVector = null;
		for(int i = 0; i < 5; i++) listTbl[i] = null;
		listTbl[inputNumber(SimAPI.H_INPUT)] = hInputs;
		listTbl[inputNumber(SimAPI.L_INPUT)] = lIinputs;
		listTbl[inputNumber(SimAPI.U_INPUT)] = uInputs;
		listTbl[inputNumber(SimAPI.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
                double maxTime = gui.getMaxPanelTime();
				long endtime = nsToDelta(maxTime * 1e9);
				if (endtime > endTime) endTime = endtime;
				double max = getEndTime();
				long endT = 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
     * decreases (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 SimAPI.resolutionScale;
    }

	/**
	 * Update the cache (beginning of window and cursor) for traces that just
	 * became visible (or were just added).
	 */
	private void updateTraceCache()
	{
		long startT = startTime;
		long cursT = firstTime;
		for(SimAPI.Node nd : theSim.getNodes())
		{
			SimAPI.HistEnt p = nd.getWind();
			SimAPI.HistEnt h = nd.getCursor();
			SimAPI.HistEnt nextH = h.getNextHist();
			if (h.getTime() > cursT || nextH.getTime() <= cursT)
			{
				if (p.getTime() <= cursT)
					nd.setCursor(p);
				else
					nd.setCursor(nd.getHead());
			}

			if (startT <= p.getTime())
				p = nd.getHead();

			h = p.getNextHist();
			while (h.getTime() < startT)
			{
				p = h;
				h = h.getNextHist();
			}
			nd.setWind(p);

			p = nd.getCursor();
			h = p.getNextHist();
			while (h.getTime() <= cursT)
			{
				p = h;
				h = h.getNextHist();
			}
			nd.setCursor(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(SimAPI.Node nd : theSim.getNodes())
			{
				SimAPI.HistEnt p = begin ? nd.getHead() : nd.getWind();
				SimAPI.HistEnt h = p.getNextHist();
				while (h.getTime() < startT)
				{
					p = h;
					h = h.getNextHist();
				}
				nd.setWind(p);
			}
			lastStart = startTime;
		}

		for(Map.Entry e : signalMap.entrySet())
		{
            SimAPI.Node nd = e.getKey();
            IAnalyzer.GuiSignal sig = e.getValue();
			if (sig == null) continue;
//		for(SimConstants.Node nd : theSim.getNodeList())
//		{
//			if (nd.sig == null) continue;

			if (t1 >= lastTime) continue;
			SimAPI.HistEnt h = nd.getWind();
			if (h == null) continue;
			int count = 0;
			long curT = 0;
			long endT = t2;
			while (curT < endT)
			{
				int val = h.getVal();
				while (h.getTime() < endT && h.getVal() == val)
					h = h.getNextHist();

				// advance time
				long nextT;
				if (h.getTime() > endT)
				{
					nextT = endT;
				} else
				{
					nextT = h.getTime();
				}

				// 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];
					IAnalyzer.LogicState [] newState = new IAnalyzer.LogicState[newTotal];
					for(int i=0; i)nd.sig).getSample(traceTime[i])==null)
//                    ((MutableSignal)nd.sig).addSample(traceTime[i], traceState[i]);
		}
		gui.repaint();
	}

	/**
	 * set/clear input status of node and add/remove it to/from corresponding list.
	 */
	private void setIn(SimAPI.Node n, char wChar)
	{
		while(n.getFlags(SimAPI.ALIAS) != 0)
			n = n.getLink();

		if (n.getFlags(SimAPI.POWER_RAIL | SimAPI.MERGED) != 0)	// Gnd, Vdd, or merged node
		{
			String pots = "lxuh";
			if (n.getFlags(SimAPI.MERGED) != 0 || pots.charAt(n.getPot()) != wChar)
				System.out.println("Can't drive `" + n.getName() + "' to `" + wChar + "'");
		} else
		{
			List list = listTbl[inputNumber((int)n.getFlags())];
			switch (wChar)
			{
				case 'h':   case '1':
					if (list != null && list != hInputs)
					{
						n.clearFlags(SimAPI.INPUT_MASK);
						list.remove(n);
					}
					if (! (list == hInputs || wasInP(n, SimAPI.HIGH)))
					{
                        n.clearFlags(SimAPI.INPUT_MASK);
						n.setFlags(SimAPI.H_INPUT);
						hInputs.add(n);
					}
					break;

				case 'l':   case '0':
					if (list != null && list != lIinputs)
					{
						n.clearFlags(SimAPI.INPUT_MASK);
						list.remove(n);
					}
					if (! (list == lIinputs || wasInP(n, SimAPI.LOW)))
					{
                        n.clearFlags(SimAPI.INPUT_MASK);
						n.setFlags(SimAPI.L_INPUT);
						lIinputs.add(n);
					}
					break;

				case 'u':
					if (list != null && list != uInputs)
					{
						n.clearFlags(SimAPI.INPUT_MASK);
						list.remove(n);
					}
					if (! (list == uInputs || wasInP(n, SimAPI.X)))
					{
                        n.clearFlags(SimAPI.INPUT_MASK);
						n.setFlags(SimAPI.U_INPUT);
						uInputs.add(n);
					}
					break;

				case 'x':
					if (list == xInputs)
						break;
					if (list != null)
					{
						n.clearFlags(SimAPI.INPUT_MASK);
						list.remove(n);
					}
					if (n.getFlags(SimAPI.INPUT) != 0)
					{
                        n.clearFlags(SimAPI.INPUT_MASK);
						n.setFlags(SimAPI.X_INPUT);
						xInputs.add(n);
					}
					break;

				default:
					return;
			}
		}
	}

	private boolean wasInP(SimAPI.Node n, int p)
	{
		return n.getFlags(SimAPI.INPUT) != 0 && n.getPot() == p;
	}

	private String pValue(String node_name, SimAPI.Node node)
	{
		char pot = 0;
		switch (node.getPot())
		{
			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(SimAPI.Trans t)
	{
		String infstr = "";
		if (irDebug != 0)
			infstr += "[" + t.describeState() + "] ";
        Collection gateList = t.getGateList();
		if (gateList != null)
		{
			infstr += "(";
			for(SimAPI.Trans tg: gateList)
			{
				SimAPI.Node n = tg.getGate();
				infstr += pValue(n.getName(), n);
			}

			infstr += ") ";
		} else
		{
			SimAPI.Node n = t.getGate();
			infstr += pValue(n.getName(), n);
		}
		return infstr;
	}

	private String prOneRes(double r)
	{
		String ret = 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(SimAPI.Trans t)
	{
        double[] resists = t.getResists();
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < resists.length; i++) {
            b.append(i == 0 ? "[" : ",").append(prOneRes(resists[i]));
        }
        return b.append("]").toString();
	}

//	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(SimAPI.Trans t)
	{
		String infstr = t.describeBaseType() + " ";
		if (t.getBaseType() != SimAPI.RESIST)
			infstr += pGValue(t);

		infstr += pValue(t.getSource().getName(), t.getSource());
		infstr += pValue(t.getDrain().getName(), t.getDrain());
		infstr += prTRes(t);
		if (t.getLink() != t && (theSim.getReport() & SimAPI.REPORT_TCOORD) != 0)
			infstr += " <" + t.getX() + "," + t.getY() + ">";
		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 gui.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 & (SimAPI.N_POTS - 1);

		System.out.println(ch + ": unknown node value");
		return SimAPI.N_POTS;
	}

	private SimAPI.Node unAlias(SimAPI.Node n)
	{
		while (n.getFlags(SimAPI.ALIAS) != 0) n = n.getLink();
		return n;
	}

	/**
	 * display node/vector values in display list
	 */
	private void pnWatchList()
	{
		theSim.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)
	{
		Collection sigs = gui.getSignals();
		for(IAnalyzer.GuiSignal sig : sigs)
		{
			IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
			if (sigsOnBus == null) continue;
			SimAPI.Node b = nodeMap.get(sig);
			if (b.getFlags(flag) != 0)
			{
				for(IAnalyzer.GuiSignal bSig : sigsOnBus)
				{
					SimAPI.Node bN = nodeMap.get(bSig);
					bN.setFlags(flag);
				}
			}
		}
	}

	private int compareVector(SimAPI.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;
			SimAPI.Node n = np[i];
			int val = chToPot(value.charAt(i));
			if (val >= SimAPI.N_POTS)
				return 0;
			if (val == SimAPI.X_X) val = SimAPI.X;
				if (n.getPot() != val)
					return 1;
		}
		return 0;
	}

	private IAnalyzer.GuiSignal findName(String name)
	{
		for(IAnalyzer.GuiSignal sig : gui.getSignals())
		{
			if (sig.getFullName().equals(name)) return sig;
		}
		return null;
	}

	/**
	 * display bit vector.
	 */
	private void dVec(IAnalyzer.GuiSignal sig)
	{
		IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
		int i = sig.getSignalName().length() + 2 + sigsOnBus.length;
		if (column + i >= MAXCOL)
		{
			column = 0;
		}
		column += i;
		String bits = "";
		for(IAnalyzer.GuiSignal bSig : sigsOnBus)
		{
			SimAPI.Node n = nodeMap.get(bSig);
			bits += n.getPotChar();
		}

		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.step(stopTime, xInputs, hInputs, lIinputs, uInputs);
			if (!repeat) break;
		}

		return theSim.getCurDelta() - 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];
			IAnalyzer.GuiSignal[] sigsOnBus = cs.sig.getBusMembers();
			if (sigsOnBus == null)
			{
				SimAPI.Node n = nodeMap.get(cs.sig);
				setIn(n, v.charAt(0));
			} else
			{
				for(int i=0; i list)
	{
		// if no arguments, get rid of all the sequences we have defined
		if (args.length == 0)
		{
			list.clear();
			return;
		}

		IAnalyzer.GuiSignal sig = findName(args[0]);
		if (sig == null)
		{
			System.out.println(args[0] + ": No such node or vector");
			return;
		}
		int len = 1;
		IAnalyzer.GuiSignal[] sigsOnBus = sig.getBusMembers();
		if (sigsOnBus != null)
			len = sigsOnBus.length;
		SimAPI.Node n = nodeMap.get(sig);
		if (sigsOnBus == null)
		{
			n = unAlias(n);
			if (n.getFlags(SimAPI.MERGED) != 0)
			{
				System.out.println(n.getName() + " 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 pTime)
		{
			System.out.println("  transition of " + n.getName() + ", 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.getName() + " . " + n.getPotChar() +
				" @ " + deltaToNS(n.getTime()) + "ns , node was an input");
		}
		else if (n.getCause().getFlags(SimAPI.VISITED) != 0)
		{
			System.out.println("  ... loop in traceback");
		} else
		{
			long deltaT = n.getTime() - n.getCause().getTime();

			n.setFlags(SimAPI.VISITED);
			pTime = n.getTime();
			cPath(n.getCause(), level + 1);
			n.clearFlags(SimAPI.VISITED);
			if (deltaT < 0)
				System.out.println("  " + n.getName() + " . " + n.getPotChar() +
					" @ " + deltaToNS(n.getTime()) + "ns   (??)");
			else
				System.out.println("  " + n.getName() + " . " + n.getPotChar() +
					" @ " + deltaToNS(n.getTime()) + "ns   (" + deltaToNS(deltaT) + "ns)");
		}
	}

	private void clearInputs()
	{
		for(int i = 0; i < 5; i++)
		{
			if (listTbl[i] == null) continue;
			for(SimAPI.Node n : listTbl[i])
			{
				if (n.getFlags(SimAPI.POWER_RAIL) == 0)
					n.clearFlags(SimAPI.INPUT_MASK | SimAPI.INPUT);
			}
			listTbl[i].clear();
		}
		for(SimAPI.Node n : theSim.getNodes() )
		{
			if (n.getFlags(SimAPI.POWER_RAIL) == 0)
				n.clearFlags(SimAPI.INPUT);
		}
	}
    
    /**
     * Returns canonic string for ignore-case comparison .
     * FORALL String s1, s2: s1.equalsIgnoreCase(s2) == canonicString(s1).equals(canonicString(s2)
     * FORALL String s: canonicString(canonicString(s)).equals(canonicString(s))
     * @param s given String
     * @return canonic String
     * Simple "toLowerCase" is not sufficient.
     * For example ("\u0131").equalsIgnoreCase("i") , but Character.toLowerCase('\u0131') == '\u0131' .
     */
    public String canonicString(String s) {
        return gui.canonicString(s);
    }

    /**
     * Method to parse the floating-point number in a string.
     * There is one reason to use this method instead of Double.parseDouble:
     * this method does not throw an exception if the number is invalid (or blank).
     * @param text the string with a number in it.
     * @return the numeric value.
     */
    public double atof(String text) {
        return gui.atof(text);
    }
    
    public int atoi(String text) {
        return gui.atoi(text);
    }
    
    /**
     * Method to convert a double to a string.
     * If the double has no precision past the decimal, none will be shown.
     * @param v the double value to format.
     * @return the string representation of the number.
     */
    public String formatDouble(double v) {
        return gui.formatDouble(v);
    }
    
	/**
	 * Convert deltas to ns.
	 */
	private static double deltaToNS(long d) { return (double)d / (double)SimAPI.resolutionScale; }
    
	/**
	 * Convert ns to deltas.
	 */
	private static long nsToDelta(double d) { return (long)(d * SimAPI.resolutionScale); }
    
    
	private static int inputNumber(int flg) { return ((flg & SimAPI.INPUT_MASK) >> 12); }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy