Monday, July 13, 2009

Topic #1 (Part 4): HDL - Simulation

Ok, so say your HDL design did not work out as planned. What can you do? Well, it turns out there are several options. The first and most primitive method is to physically interact with your FPGA and try to determine what the root cause of the bug is. Maybe you decide to slow down the input clock to your system and turn on a few LEDs as indicators of important variables.
The second and most advanced method is to implement a Chipscope "core" on your FPGA. Chipscope is a program Xilinx offers that allows you to physically analyze HDL code directly on your FPGA. Unfortunately if you want this feature you will have to dish out some cash, as it is licensed. But the really nice thing about it is the fact that it gives you the "actual" results as apposed to the third option below. A "core" is an IP (intellectual property) that you can instantiate into your HDL code to give the FPGA additional functionality. Think of cores as mini-programs for your FPGA.
The third and last method is to simulate in software. A major plus is that Xilinx and Altera provide these features for free. To simulate, you need to design what is called a "testbench", testbenches are additional snippets of HDL code that stimulate the input signals (i.e. clock signals) such that the actual HDL code that you are trying to test has a clue as to when and how frequent to update signals and registers.

I will give you a step by step procedure for setting up a testbench in Xilinx ISE using the previous dff (D Flip Flop) HDL code, which I re-posted below for clarity.

module dff(clk,d,q,qn);
input clk, d;
output q, qn;
reg q=0;
reg qn=1;
always @(posedge clk)
begin
q<=d;
qn<=~d;
end
endmodule


It should be noted that it DOES NOT matter which variant you choose for your HDL code (i.e. Verilog or VHDL). As long as the I/O ports and variables are the same you can simulate the exactly the same way.


Step 1: Add the testbench module.
You have the choice to add a VHDL testbench or Verilog testbench. Choose which ever one you are more comfortable with. To do this you:

  • Right click on your module name in the "Sources" window with the "Sources for:" set to "Implementation".
  • Select "New Source".
  • Select either the "Verilog Test Fixture" or the "VHDL Testbench" (I used the Verilog Test Fixture in this example)
  • If you have more than one module in your project you will be prompted for which module to associate this test bench with. Select the appropriate one.
  • Finish up with the rest of the prompts and Xilinx will make a template for you. It will look like:

module testbench;

// Inputs
reg clk;
reg d;

// Outputs
wire q;
wire qn;

// Instantiate the Unit Under Test (UUT)
dff uut (
.clk(clk),
.d(d),
.q(q),
.qn(qn)
);

initial begin
// Initialize Inputs
clk = 0;
d = 0;

// Wait 100 ns for global reset to finish
#100;

// Add stimulus here

end

endmodule



Step 2: Add the stimulation code
By definition all inputs will need some stimulation and all outputs, registers, signals need to be initialized. To do this you will need to do something like this:

module testbench;
// Inputs
reg clk;
reg d;

// Outputs
wire q;
wire qn;

// Instantiate the Unit Under Test (UUT)
dff uut (
.clk(clk),
.d(d),
.q(q),
.qn(qn)
);

initial begin
// Initialize Inputs
clk = 0;
d = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here

// Input Generation
#10 d = 1;
#10 d = 0;
#10 d = 1;
#10 d = 0;
#10 d = 1;
#100 d = 0;
#50 d = 1;
#60 d = 0;

// Console Output
$timeformat(-9,1,"ns",12);
$display(" Time Clk pushbutton");
$monitor("%t %b %b", $realtime, clk, d);
end

// Declare a clock period constant.
parameter clockPeriod = 100;

// Clock Generation
initial begin
forever clk = #(clockPeriod / 2) ~ clk;
end

endmodule


  • So the code that was added to the testbench achieves several functions that we need/want.
  • First, we declare a clockPeriod parameter. You don't necessarily need a clock period parameter, it is mainly to help keep things verbose. Most parameters, if they deal with time, are generally measured in nanoseconds. In this case we created a parameter called "clockPeriod" that is given a value of 100. The value is technically unitless at this point in time but when applied to timing constraints it will gain the unit "ns"
  • Next we generate the clock signal. More specifically, we generate the clock edges. First we use "initial begin" to indicate another process that will continually execute each iteration and then follow that with the "forever" keyword. This says that we re-execute the statement after a period of time each iteration. The syntax is a little strange but what this says is:

During each iteration, after clockPeriod/2 nanoseconds take the clock signal and invert it.


This is one of the most basic clock generation schemes you can use in a testbench. The "#" is a "WAIT" operator that waits a period of time until executing the next sequential statement.

  • By using the wait operator we can make a more interesting signal for the input signal d (instead of using a periodic signal). By using a sequence of these wait statements followed by d=0; and d=1; statements, we can create any sequence we need to help prove that the code is working as expected.
  • The last thing that we might want to add is some output to the console window that gives you the results in text format. To do this we use console functions by using the console operator "$". There are many functions that you may want to use, in this testbench, I used $timeformat, $display, and $monitor. The $timeformat function allows you to specify the format of the realtime simulation, $display allows you to output text to the console, and $monitor allows you to output simulation variables to the console window.

Step 3: Simulate
Now that the test bench has been coded, we can now move on to the actual simulation! To simulate, go to the "Processes" window and select the "Processes" tab if it isn't selected already and double click "Simulate Behavioral Model". If all went according to plan, you will see some output in the console window and a plot of a nice timing diagram as seen below.

If you see some of your signals crossed out such that you can't observed their transitions, then chances are you have not initialized some registers in your primary HDL code. If a signal depends on another signal that has not been set to an initial value, then the simulation will not be able to determine a starting point. The interesting part about this is that this does not matter to a physical system. Most systems will assume a logic low or high upon power up.

Hopefully everything went to plan and you have a working simulation of your DFF. There is a lot to the simulation that I did not explain or touch, go ahead and explore what other functionalities the simulator contains.

Coming up shortly, I will discuss how to create the "ufc" file, generate the "bit" file, and program your FPGA in iMPACT.

1 comment:

  1. Thanks for sharing this valuable piece of information with us. I am glad to find this stuff here. Keep up the good work.pcb suppliers

    ReplyDelete