The interactive stimulator is a tool that can be used with your
test bench to interactively (as opposed to programmatically)
stimulate the top-level port wires of your design. Don't get it
confused with the simulator. A stimulator does what the name
indicates - it stimulates wires by driving them high or low.
interactive stimulator, all of the values on the top-level wires
must be done with calls to the
put method of the
Wire class within the clock method.
This programmatic approach is usually a more static approach. Programmatic wire stimulation has advantages and disadvantages. On the pro side, programmatic wire stimulation allows for precise and consistent design simulation. On the con side, it hinders experimentation since the test bench usually must be recompiled after every little modification to the sequence of puts.
With the interactive stimulator you don't have to recompile your test bench in order alter the sequence of puts on port wires. The puts can be determined interactively during simulation. And the interactive stimulator also still maintains the precise and consistent advantages of statically programmed stimulation.
In the Getting Started tutorial and in the cvt documentation you already were introduced to interactive stimulators without knowing it. When you use dtb to load a circuit as described there, stimulators are automatically created for all top level port wires in your design. In this section, you will learn how to use stimulators in test benches.
This tutorial describes how to the use the interactive stimulator in JHDL. There are two simple steps to using the interactive stimulator:
To set up your JHDL TestBench to use the interactive stimulator, you need to import the Stimulator class. Just include the following at the top of your TestBench file:
import byucc.jhdl.apps.Stimulator.Stimulator; import java.util.Properties;
The second line is needed if you are using the Properties class to initialize put schedules (covered later).
Now, use the
new operator in
Java to instance a Stimulator object:
Stimulator stimulator = new Stimulator( this );Stimulator is a subclass of Logic and will become a child cell of your testbench along with the design encapsulated by the testbench.
Now, add wires you want to be able to interactively stimulate (wires portAIn and portBIn) to the stimulator object:
stimulator.addWire( portAIn ); stimulator.addWire( portBIn );
Both wires will initially have a constant value of 0 until you interactively change them with a put command in cvt. Once you start up cvt you can change wire values by typing into the command input window like this:
put portAIn 7 put portBIn 4
Alternatively, when you add a wire to a stimulator, you can provide a repeating put schedule like this:
stimulator.addWire( portBIn, "0 1 2 2 1" );
In this case, portBIn will initially be set up to repeatedly cycle through the values "0 1 2 2 1", one per clock cycle. This repeating pattern can be changed later with an interactive put command in cvt. Also, from cvt you can do a put command to set up a repeating pattern as well:
put portBIn 0 1 2 2 1
To summarize, you first create a stimulator object and then register wires with it. There are several constructors available to instance the Stimulator. All require a parent Cell (your TestBench). Nearly all constructors also allow you to add your wires to the stimulator in the constructor itself rather than having to call it separately. See the JHDL API documentation on byucc.jhdl.apps.Stimulator for more details.
NOTE: When creating your wires in JHDL, it may be useful to give them a specific name so that you will know for sure how to access them through the command-line interface.
This example shows the contents of a Properties file and the code
from a TestBench that instantiates a Stimulator for some wires.
The syntax of java.util.Properties file can be found in the
description of the
load method of that class.
schedules.props file contents:
# This file contains the schedules for the inputA and inputB wires of my TestBench inputA = 0 1 1 1 0 1 0 15 inputB : 10 9 8 7 5 4 3 2 1 15
Portions of the TestBench class:
/* Declare the wires */ Wire inputA; Wire inputB; Wire inputC; ... /* Bind the wires to the ports */ /* Put the wires in a Collection object, such as a HashSet */ java.util.HashSet stimulatorWires = new java.util.HashSet(3); stimulatorWires.add( inputA ); stimulatorWires.add( inputB ); /* Make a Stimulator with this TestBench as parent */ /* The wires are passed to it in a Collection object */ /* The schedules will be loaded from the Properties file given */ Stimulator stimulator = new Stimulator( this, stimulatorWires, "schedules.props" ); /* We can still add more wires but we have to specify the schedule if we want a non-default schedule (i.e. the schedules in the Properties file are no longer available) */ stimulator.addWire( inputC, "5 8 1 0 15" );
This example is a bit complex in that the wires created are all placed into a Collection (in this case a HashSet). This is so we can simply pass the Collection of wires along with the name of the property file to the Stimulator constructor.
Also, for information on special considerations when using Stimulators on tri-state buses, see the tri-state section in this document. All of the above examples use JHDL's default clocking. Since there is only one clock, it is clear when the elements of the schedule are put onto the wire - there will be one element put per cycle of the default clock. In a multi-clock environment you may want to have different wires on different clock schedules. To associate a Stimulator with a different clock schedule, simply set the default clock before instantiating the stimulator:
/* Declare the wires */ Wire portAIn; Wire portBIn; Wire clockA, clockB; ... /* Make a Stimulator with this TestBench as parent and which will operate on clockA's schedule*/ setDefaultClock( clockA ); Stimulator stimulator = new Stimulator( this ); /* Add portAIn */ stimulator.addWire( portAIn ); /* Make a different Stimulator on clock schedule B */ setDefaultClock( clockB ); stimulator = new Stimulator( this ); /* Add portBIn with custom put schedule: 0, 1, 2, 2, 1, 0, 1, 2, 2, 1, etc. */ stimulator.addWire( portBIn, "0 1 2 2 1" );
It is important to note that Stimulators are themselves merely JHDL circuit elements; in fact Stimulators are just instances of the class byucc.jhdl.Logic.Logic. As Logic elements, Stimulators are clockable. Therefore, even if your entire design is purely combinational, if you have Stimulators driving your design, you will have a clock in the system. By default, the Stimulators simply use the current default clock. Stimulators are by default rising-edge triggered; currently, there is no support for making a Stimulator falling-edge triggered.
Sometimes a user design uses explicit clocks or needs to have a unique clock schedule (the pattern, including duty cycle, etc. of a clock wire's driver). If your design uses explicit clocks or if it sets the default clock, then you must also make sure that you set up the clock for the Stimulator. JHDL does not allow designs to mix explicit with implicit clocks. The Stimulator just uses the default clock available to it at build time; if the clock hasn't been set prior to building the Stimulator, it uses the global default clock made available by the HWSystem. But if your design uses explicit clocks, you must make sure that you set the default clock before you instance a Stimulator. Also, make sure that all of your clocks have the same length of schedule.
Stimulators should typically only be clocked by wires that are the outputs of a clock driver. (i.e. avoid using gated clocks and other unusual clock wires for Stimulators.) Also, to avoid problems with clocking Stimulators, it is a good idea to build the Stimulators last. By making sure that the TestBench builds your design and any other circuitry before instancing a Stimulator, you help to ensure that the Stimulator will be properly clocked.
Summary of using clocks with Stimulators:
This is definitely an advanced section and should only be attempted after you have successfully used tri-state devices in a design.
In order to be allowed to drive a tri-state bus wire, a JHDL cell must implement the TriStateDriver interface. When a tri-state bus wire is added to a Stimulator, a new Stimulator that implements the TriStateDriver interface is created to handle that wire. That one Stimulator is then responsible for only that one wire. In order to ensure that the Stimulator recognizes that a wire is a tri-state bus, it is essential that the wire is connected to another TriStateDriver, a pullup, or a pulldown before it is added to a Stimulator. Alternatively, you can instance a TriStateStimulator directly. (The constructor for a TriStateStimulator takes a parent Node, the Wire, and a String for the schedule, in that order.)
If at any time a tri-state bus Wire being driven by a Stimulator is to let the wire float or allow some other device to drive it, the schedule for that wire at that point should issue a "Z". That is, if you use the standard ValueForcers to generate the value sequence for the wire, indicate a high impedance output with "Z" in your schedule string. For custom ValueForcers (see the section on function generators), make sure the underlying ValueProvider properly implements the isDrivingOutput() method appropriately. See the API documentation for more information.
As shown above, you can specify a put schedule for a wire when you add it to a stimulator. If the put schedules placed on the wires this way in the TestBench are what you want to simulate in JHDL, you do not need to do anything else with the interactive stimulator. You may simply cycle the simulation normally.
If you do want to interactively update the schedules on the wires, you can use the JHDL command-line interface (CLI). These commands are entered in the cvt text input window. The interactive stimulator registers two commands in the JHDL CLI. It is through these commands that you interact with the stimulator.
putlist       The putlist command is used to display the names of the wires that are currently registered with any Stimulator object. This helps you understand what the schedules are for the various wires.put       The put command is used to create or update a custom schedule for a given wire. The syntax is:
put wire_name value|scheduleA value is a decimal, hexadecimal, octal, or binary value (prefix 0x, 0o, or 0b for hexadecimal, octal, or binary). A value may also be Z. (Useful for inout ports.) A schedule is a space-separated list of values. A schedule may also be the name of a custom function generator object along with appropriate arguments for it. See the advanced section for more information on custom function generator schedules.
The following are examples of calls to the
put myWire1 0b110
myWire1with the value 6 on every clock cycle.
put myWire2 0b110 0x10 8 0o12
myWire2with the sequence of values 6, 16, 8, and 10. On the first clock cycle, the stimulator will drive the wire with a 6, on the second, with a 16, on the third, an 8, on the fourth, a 10. Then the process repeats so that on the fifth cycle, the stimulator will drive the wire with a 6, and so forth.
The following files contain a full JHDL example that uses the
interactive stimulator. With the JHDL classes or JHDL.jar in your
classpath, compile AndNReg and tbAndNRegStimulator. Then execute
tbAndNRegStimulator with the
javac tbAndNReg3BitStimulator.java AndNReg3Bit.java java tbAndNReg3BitStimulator -gui
|AndNReg3Bit.java||This is the design that is wrapped by the TestBench|
|tbAndNReg3BitStimulator.java||The TestBench for this example. This is where the Stimulator is created.|
|sched.props||This is a Properties file that is used by this example|
The following files contain a another example that uses the interactive stimulator. With the JHDL classes or JHDL.jar in your classpath, compile CustomClockCell and tbCustomClockCell. Then execute tbCustomClockCell:
javac tbCustomClockCell.java CustomClockCell.java java tbCustomClockCell
|CustomClockCell.java||This is the design that is wrapped by the TestBench|
|tbCustomClockCell.java||The TestBench for this example. This is where the Stimulator is created. This TestBench uses custom, user-defined clocks and a tri-state Stimulator. This TestBench is not as full-featured as tbAndNReg3BitStimulator; it is meant to show how to deal with user-defined clocks and tri-state wires.|
The Stimulator also allows you to create your own custom function generator to provide the values to put on an input wire. To create a custom function generator, simply create a class that implements one of the sub-interfaces of byucc.jhdl.apps.Stimulator.ValueProvider. Then, to apply your function generator to a wire during simulation, use the put command.
The put command has the following syntax:
help putfor more information on the syntax of the arguments to create a ValueProvider. Use this same syntax when creating a ValueProvider for the Wire from within the TestBench. The example at the end of this section demonstrates how to do this.
There are four different sub-interfaces of the ValueProvider interface. These interfaces, which are also in the byucc.jhdl.apps.Stimulator package, are BooleanValueProvider, IntegerValueProvider, LongValueProvider, and BVValueProvider. These interfaces are designed so that, if necessary, you can implement all four, or any combination. Having four different interfaces is desirable to allow you to select the interface that most closely matches your design. For one-bit wires, the BooleanValueProvider interface is sufficient; but for wires up to 32 bits wide, you should probably use the IntegerValueProvider. Likewise, LongValueProvider is adequate for wire widths up to 64 bits and BVValueProvider can be used for arbitrary-width wires.
Each ValueProvider interface requires you to implement two versions
of the method
getForceSchedule method takes an
be used as a radix. The other takes a
String to be
used as a BV format string. Use these methods to output a
String that will represent the series of values or the
function that your ValueProvider generates.
Each ValueProvider interface also requires you to implement the
getReset[ReturType]Value(), where return_type is one
of boolean, int, long, or BV, and ReturnType is Boolean, Integer,
Long, or BV respectively. Use the getNext[ReturnType]Value method
to provide successive values of your function for each clock
cycle. Use the getReset[ReturnType]Value method to provide the
value that the wire should have at system reset.
Once you have written and compiled your function generator, you can
apply it to your wire using the put command from the command line
in the circuit visualization window of JHDL. The put command has
been overloaded to allow you to either put a single value or series
of values (as described above) or to
instance a ValueProvider and associate it with a wire. Run the
help put to view the
syntax and other helpful information. The syntax of this use of
the put command allows you to specify which (public) constructor of
your ValueProvider class (if it happens to have more than one
constructor) and which of the ValueProvider interfaces you wish it
to act as during simulation (if it happens to implement more than
one). You may also provide arguments to the constructor of your
ValueProvider to set up any parameters it may have.
The following files contain a full JHDL example that uses the
interactive stimulator and a custom function generator. With the
JHDL classes or JHDL.jar in your classpath, compile AndNRegNBit,
tbAndNReg32Function, and Cosine. Then execute tbAndNReg32Function
javac tbAndNReg32Function.java AndNRegNBit.java Cosine.java java tbAndNReg32Function -gui
|AndNRegNBit.java||This is the design that is wrapped by the TestBench.|
|tbAndNReg32Function.java||The TestBench for this example. This is where the Stimulator is created and a custom function generator is associated with the wires.|
|Cosine.java||A custom function generator that will output a cosine function.|
|CustomCosineView.java||A custom viewer to watch wires with cosine values on them.|
|| JHDL Home Page | Configurable Computing Lab | Prev (TestBenches) | Next (Advanced Netlisting) ||
Copyright (c) 1998-2003 Brigham Young University. All rights reserved.
Last updated on 11 May 2006