![]() |
|
|
// Called each time the simulator resets public void simulatorReset(); // Called each clock step after the circuit settles public void simulatorUpdate(int cycle, int phase); // Called each time the JHDL system deems a refresh of all // GUI elements is warranted (i.e. after a simulation run which // could be of multiple cycles) public void simulatorRefresh(int cycle, int phase);
import byucc.jhdl.base.*; import byucc.jhdl.Logic.*; // Class name is TestSimCallback. It implements the SimulatorCallback interface... public class TestSimCallback extends Logic implements SimulatorCallback { public static CellInterface[] cell_interface = { out ( "q", "WID" ), param ("WID", INTEGER), }; Wire q; // This is just the constructor as normal public TestSimCallback( Node parent, Wire q, String instanceName ) { super(parent, instanceName); bind("WID", q.getWidth()); this.q = connect("q", q); // Build a simple counter... Wire s = wire(q.getWidth(), "sum"); add_o(q, constant(q.getWidth(), 1), s, "addn"); reg_o( s, q, "cntOut"); } // The SimulatorCallback interface stuff follows public void simulatorReset() { } public void simulatorRefresh(int cycle, int phase) { } // Print results to screen as well public void simulatorUpdate(int cycle, int phase) { System.out.println("Cycle = " + cycle + ", Phase = " + phase + ": " + q.get(this)); } }
What is being done is that the simulatorUpdate() method is being used to print out the current state of the circuit. The simulator will call this method every step after the circuit has stabilized. The phase variable is used to count clock steps within a cycle. And the cycle variable is used to count clock cycles. See the simulator documentation for more on how the steps and cycles of the simulator relate to each other.
This same capability has been successfully used to do complex validation of stream-based DSP designs that would be extremely difficult to do by looking at waveforms. For example, consider a system where data arrives infrequently and must be converted from serial to parallel format before any other meaningful processing occurs. The simulatorUpdate() method can test the circuit's internal signals each clock cycle and print out key circuit values only on clock cycles when something of interest occurs (a conversion has completed). In addition, this output can be printed in a format that a tool such as Matlab could read in and post-process or plot. It often makes sense to also convert the bits in the circuit to their equivalent floating point representations for viewing (the JAB tools have only integer types available for display).
// The SimulatorCallback interface stuff follows TestFrame tf; // Frame to hold cycle count in GUI public void simulatorReset() { // Create a testFrame if one doesn't exist yet if (tf != null) tf.dispose(); tf = new TestFrame(); } // Update information in TestFrame public void simulatorRefresh(int cycle, int phase) { tf.updateValues(q.get(this)); } // Print results to screen as well public void simulatorUpdate(int cycle, int phase) { System.out.println("Cycle = " + cycle + ", Step = " + step + ": " + q.get(this)); } }
Assuming a graphical viewer class named TestFrame has been defined, this code will create the frame on reset and then update it with new values by calling its updatevalues() method each cycle. When running in single step mode in JAB, the TestFrame will then be updated with a new value each cycle.
tb_TestSimCallback.java The testbench of the 4-bit counter example...
TestSimulatorCallback.java A 4-bit counter...
TestFrame.java
The GUI element for the 4-bit counter SimulatorCallback example...
| JHDL Home Page | Configurable Computing Lab | Prev (Advanced Netlisting) | Next (Advanced Clocking) | |
JHDL 0.3.45
Copyright (c) 1998-2003 Brigham Young University. All rights reserved.
Last updated on 11 May 2006