Behavioral Modeling in JHDL
JHDL allows the user to write an optional behavioral model for any Structural
cell. This capability is provided for a number of purposes:
- All library primitive elements are behaviorally modelled. If you
want to add new primitives to JHDL you will create behavioral models
for them.
- Once a complex module such as a multiplier is debugged, a
behavioral model of it can be used in subsequent simulations of
designs using it. This will make the simulations run much faster.
- For complete applications, it is often to simulate the entire
system the FPGA is embedded in. This would include the behavior of
on-board memories, FIFO's, etc. These can be modelled either as
structural or behavioral elements.
Example
The following is an example of a simple behavioral model of a cell
with four inputs a, b, c and d and one output e. The circuit implements
the following function: ab or cd and is a combinational design.
import byucc.jhdl.base.*;
import byucc.jhdl.Logic.*;
public class behav1 extends Logic {
public static CellInterface[] cell_interface = {
in("a",1), in("b",1), in("c",1), in("d",1),
out("e",1)
};
private Wire a,b,c,d,e;
protected boolean defaultSimulationModelIsBehavioral(){
return true;
}
public behav1(Node parent, Wire a, Wire b, Wire c, Wire d, Wire e) {
super(parent);
this.a = connect("a",a); this.b = connect("b",b);
this.c = connect("c",c); this.d = connect("d",d);
this.e = connect("e",e);
clockMethodIsDisabled(true);
propagateMethodIsDisabled(false);
}
public void propagate(){
e.put(this,(a.get(this) & b.get(this)) | (c.get(this) & d.get(this)));
}
public void reset(){
e.put(this,0);
}
}
Note the following about this code:
- The function defaultSimulationModelIsBehavioral() is
defined to return true to signal to the simulator that this is a
behaviorally modelled cell.
- Instead of building a circuit in the body of the constructor, it
simply calls functions to disable the clock method and to enable the
propagate method. Synchronous cells require a clock method while
combinational cells require a propagate method.
- The propagate method simply computes the output as a function of
the inputs. The reset method simply outputs a zero.
This can now be used like any other cell. Just be sure you don't try
to netlist with it included in your design.
A second example is given below. It is a counter but with an
asynchronous reset.
import byucc.jhdl.base.*;
import byucc.jhdl.Logic.*;
public class behav2 extends Logic {
public static CellInterface[] cell_interface = {
in("clr",1), in("inc",1),
out("q",4)
};
private Wire clr, inc, q;
protected boolean defaultSimulationModelIsBehavioral(){
return true;
}
public behav2(Node parent, Wire clr, Wire inc, Wire q) {
super(parent);
this.clr = connect("clr",clr);
this.inc = connect("inc",inc);
this.q = connect("q",q);
clockMethodIsDisabled(false);
propagateMethodIsDisabled(false);
}
int val = 0;
public void clock() {
if (clr.get(this) == 1)
val = 0;
else if (inc.get(this) == 1)
val++;
q.put(this, val);
}
public void propagate(){
if (clr.get(this) == 1)
val = 0;
q.put(this, val);
}
public void reset(){
val = 0;
q.put(this, val);
}
}
In this case, both the clock and propagate methods are enabled. The
clock and propagate methods then maintain a counter of the current
counter state and put that value onto the output wire as requested.
Modeling Methods (used to create JHDL behavioral simulation
models)
There are four methods that implement and enable behavioral models
in JHDL Structural (Logic) cells. These are:
-
public void reset() -- this method must implement the behavior of
the circuit when the global reset is asserted.
-
public void clock() -- This method must implement any behavior that
is synchronous to the global clock.
-
public void propagate() -- This method must implement any behavior
that is combinatorial.
-
public boolean defaultSimulationModelIsBehavioral() -- This function
must be overloaded to return true if the user desires the behavioral model
to be the default. If this is not overloaded as such, the simulation model
will still be available, however, it will have to be enabled manually at
simulation time. See the example below.
If your circuit is purely synchronous, you will need to implement the
clock() and reset() methods. A purely asynchronous circuit need only
implement the propagate() method. If the circuit you are modeling
contains both synchronous and asynchronous behavior, then you will
need to implement all three methods.
In some cases it may be necessary to individually enable or disable the
clock()
or propagate() methods when implementing module generators. For
example, the designer of a module generator may wish to provide both registered
and non-registered versions of a multiplier. When the registered version
of the multiplier is desired, the clock() method must be enabled
and the propagate method must be disabled. If a non-registered version
of the multiplier is desired, the clock() method must be disabled
and the
propagate() method must be enabled. The following methods
are defined on Structural (Logic) cells and provide this capability.
-
public boolean clockMethodIsDisabled(boolean) -- To disable the
clock method, invoke clockMethodIsDisabled(true); to enable it,
invoke clockMethodIsDisabled(false).
-
public boolean propagateMethodIsDisabled(boolean) -- To disable
the propagate method, invoke propagateMethodIsDisabled(true);
to enable it, invoke propagateMethodIsDisabled(false).
Note that you are not allowed to simultaneously disable the
clock()
and propagate() method -- at least one of these methods must be
enabled. An exception will be thrown if you attempt to disable both the
clock() and
propagate() methods.
Controlling Which Model is Used for
Simulation
There are 4 methods supplied that can be used written
directly into your Java code to control what is simulated behaviorally
and what is simulated structurally. All of these methods are defined
on Cells. These methods are:
-
public void enableBehavioralModel() -- this method can be called
on a Cell and can be used to enable behavioral models on an instance-by-instance
basis. When invoked on a Cell, this method will enable the behavioral model
for this Cell on the next simulation run. As a side effect, this will disable
all of the behavioral models for the children of this Cell. If there is
no simulation model available for this Cell, an exception is thrown.
-
public void disableBehavioralModel() -- this method can be called
on a Cell and can be used to disable behavioral models on an instance-by-instance
basis. When invoked on a Cell, this method will disable the behavioral
model for this Cell on the next simulation run. As a side effect, this
will enable the behavioral models for all the children of this Cell. If
the Cell is a leaf cell, this will throw an exception.
-
public void disableAllBehavioralModels() -- this method can be called
on a Cell and can be used to disable all behavioral models for this Cell
and all of its children (except the leaves) resulting in a purely structural
simulation.
-
public void resetBehavioralModelstoDefaults() -- when invoked on
a Cell, this method resets all of the simulation models to their defaults
as defined by the designer of this Cell, for this specific Cell.
If you are using Jab, then you can control the behavioral state of any
cell at runtime by using the Jab GUI (look here
for more information), or the behave command
(look here for more
information) and do not need to build the calls directly into your
Java code.
General Strategy
When writing behavioral models, the class will need to keep references
to all the wires connected in the connect() calls. You must keep
references to the wires returned from the connect()
calls. If you do not do this, then you will not be able to read or
write the wires.. To read and write wires, you use the
get() and put() methods, respectively. There are many
different versions of these methods, depending on your wire width.
Please refer to the Wire API documentation to
find more information on these calls:
get,
getA,
getB,
getBV,
put,
putA,
putB, and
putBV
Non-simulateable and Non-netlistable Cells
In come cases, it is useful to flag a cell as non-simulateable
or non-netlistable. This is useful when one structural cell is to
be used for simulation, and another is used for netlisting.
Many JHDL library cells that cannot be simulated effectively
are marked as non-simulateable. All cells built in the library in
such a situation have already been flagged appropriately. For
example, an FMAP cell (that controls LUT packing) does not
need to be simulated, but must be netlisted.
On rare occasions, it is necessary to work have a structural
simulation model and a separate, different, netlisting model. In
this case, these properties can be set directly on a cell.
-
public void Cell.isNetlistable(boolean) -- this method
can be invoked on a cell to flag it specifically as
netlistable or not.
-
public void Cell.isSimulateable(boolean) -- this method
can be invoked on a cell to flag it specifically as
simulateable or not.
JHDL 0.3.45
Copyright (c) 1998-2003 Brigham Young University. All rights reserved.
Last updated on 11 May 2006