Showing posts with label Tutorials. Show all posts
Showing posts with label Tutorials. Show all posts

Wednesday, June 5, 2013

Stimulus Generation in VHDL

General Structure for Simulation


a) UUT: Test Component Instantiation
b) Signals to generate stimulus
c) assert statements 

1. A simple template for stimulus generation in VHDL is:

Here is a simple stimulus which would test a 2x2 multiplier

Notice that in the process below, there is no sensitivity list and it uses wait statements.


---------- Stimulus to DUT-----
stim:process
begin
A <= "00";
B <= "00";

wait for 10 ns;
A<= "01";
B<= "01";

wait for 10 ns;
A <= "10";
B <= "10";

wait for 10 ns;
A <= "11";
B <= "11";

 wait;

end process stim;

Note: "Wait;" is an important statement at the end. If not for this, stimulus will be generated repeatedly and will enter into infinite loop. This might be OK if it is exactly what you want.
I will update the post to have more advanced stimulus generation styles in future such as reading stimulus for text file, using python to generate stimulus.

1a. Improvement# 1

A little bit better approach to above stimulus generation is shown below. We declare a constant which is called "period" with default value of 10 ns.

---------- Stimulus to DUT-----
stim:process
constant period: time := 10 ns;
begin
A <= "00";
B <= "00";
wait for period;
A<= "01";
B<= "01";

wait for period;
A <= "10";
B <= "10";

wait for period;
A <= "11";
B <= "11";

wait;

end process stim;

2. Improvement #2

While the above example 1a shows how to create stimulus, it lacks code check the response from the dut and ensure that it is indeed working as expected. How do we check correctness of the response?

One approach is to use assert statements
assert (dut response = expected response); If dut response is not equal to expected response, assert will throw an error.

e.g., for stimulus wait for 10 ns;
A<= "01";
B<= "01";

We expect the output to be 0001. So, we would write the statement as
assert (P = "0001") report "TEST FAILED";
An example code is shown below:
---------- Stimulus to DUT-----
stim:process
constant period: time := 10 ns;
constant update: time := 1  ns;
begin

-- Case#1:
wait for period;
A <= "00";
B <= "00";
wait for update;
assert (P = "0000")report "TEST FAILED" severity error;

-- Case#2:
wait for period;
A<= "01";
B<= "01";
wait for update;
assert (P = "0001")report "TEST FAILED" severity error;

-- Case#3:
wait for period;
A <= "10";
B <= "10";
wait for update;
assert (P = "0010") report "TEST FAILED" severity error;

-- Case#4:
wait for period;
A <= "11";
B <= "11";
wait for update;
assert (P = "1001") report "TEST FAILED" severity error;

wait;
end process stim;


3. Improvement#3

While the above approach is nicely structured, it is cumbersome to write all the statements every time. Also, there is a regularity in the stimulus vector. A better approach would be to store all the stimulus elements in a vetcor/array and read the stimulus from vector/array using a for loop

---------- Stimulus to DUT-----
stim:process
constant period: time := 10 ns;
constant update: time := 1  ns;
begin

--- Apply Stimulus recursively
for i in 0 to 3 loop
    wait for period;
    A <= CONV_STD_LOGIC_VECTOR(i,2);
    B <= CONV_STD_LOGIC_VECTOR(i,2);
    wait for update;
    assert (P = i*i)report "TEST FAILED" severity error;
end loop;

wait;
end process stim;

In this case I have shown how you could create stimulus on the fly using for loop and apply to the DUT. However, there will be situations where you want to precalculate the stimulus through some other code and store in file.

Note: For some debugging purposes, you want to print out the input values when a test case fails. Often times, the input value is a std_logic_vector. To convert std_logic_vector use "integer'image(CONV_INTEGER(unsigned(a)))"

4. Improvement# 4: Make a Simpkg, printing objects in VHDL
Start adding all the utility functions for testbenches such as vec2str, std2str into a package so that it can be reused. To print variable i of integer type use, integer'image(i);

Tutorial: Printing Objects in VHDL
http://www-ee.uta.edu/Online/Zhu/spring_2007/tutorial/how_to_print_objexts.txt

5. Improvement# 5: Assert in multiple lines

Assert statement in VHDL by default only allows one line. To break it into multiple lines use concatenate  (&) operator

e.g.,  assert (y= remainder(0)) 
  report "Test Failed" &
  "dut y =" & std2str(y) & " expected y =" & std2str(remainder(0))

  severity error;

5. Random Value Stimulus in VHDL Testbenches
The IEEE "math_real" VHDL package supplies a function called "UNIFORM" which returns a pseudo-random number (of type REAL) in the range 0 to 1.0. 

Using Packages in VHDL

Today, I was playing with code to write 2 x 2 multiplier. In the process of writing code for the multiplier, I had to use couple of full adders and half adders. Normally, I would write code for the full adder and half adder in separate files and declare them as components in my main file.

Code Style #1: mult2x2.vhd

library ieee;
use ieee.std_logic_1164.all;
use work.adderpackage.all;

entity mult2x2 is
    port (
        A,B    :    in        std_logic_vector(1 downto 0);
        P    :    out        std_logic_vector (3 downto 0)
    );
end entity mult2x2;

architecture RTL of mult2x2 is
    signal p00,p10,p01,p11: std_logic;
    signal c1,c2:std_logic;
    
    --- Full Adder Circuit
    component fa
        port(a, b, cin : in  std_logic;
             s, cout   : out std_logic);
    end component fa;
    
-- Half Adder Circuit
    component ha
        port(a, b    : in  std_logic;
             s, cout : out std_logic);
    end component ha;
begin

p00 <= A(0) and B(0);
p01 <= A(1) and B(0);
p10 <= A(0) and B(1);
p11 <= A(1) and B(1);

P(0) <= p00;
S0:component ha
    port map(a    => p01,
             b    => p10,
             s    => P(1),
             cout => C1);
             
S2:component ha
    port map(a    => C1,
             b    => p11,
             s    => P(2),
             cout => c2);
P(3) <= c2;

end architecture RTL;



However, adding the component instantiations into the main code makes the code look bloated. To simply the code, we can put the component declaration into packages (very similar to header file) and import the package (header file) into main code.

The code below shows how it is done:
Coding Style #2: Mult 2x2


library ieee;
use ieee.std_logic_1164.all;
use work.adderpackage.all;

entity mult2x2 is
    port (
        A,B    :    in        std_logic_vector(1 downto 0);
        P    :    out        std_logic_vector (3 downto 0)
    );
end entity mult2x2;

architecture RTL of mult2x2 is
    signal p00,p10,p01,p11: std_logic;
    signal c1,c2:std_logic;
begin

p00 <= A(0) and B(0);
p01 <= A(1) and B(0);
p10 <= A(0) and B(1);
p11 <= A(1) and B(1);

P(0) <= p00;
S0:component ha
    port map(a    => p01,
             b    => p10,
             s    => P(1),
             cout => C1);
             
S2:component ha
    port map(a    => C1,
             b    => p11,
             s    => P(2),
             cout => c2);
P(3) <= c2;

end architecture RTL;


adderpackage.vhd
library ieee;
use ieee.std_logic_1164.all;

package adderpackage is

--- Full Adder Circuit
  component fa
    port(a, b, cin : in  std_logic;
       s, cout   : out std_logic);
  end component fa;
  
-- Half Adder Circuit
  component ha
    port(a, b    : in  std_logic;
       s, cout : out std_logic);
  end component ha;
    
end package adderpackage;

package body adderpackage is
  
end package body adderpackage;

Thursday, May 23, 2013

Step 1: Getting LED's blink on Digilent ATLYS Board (Xilinx Univeristy Program)

I have been fascinated with power of FPGA's when I started using them for computation application. My programming experience with programming FPGA's using LabVIEW FPGA. National Instruments becomes excellent PXI based FlexRIO boards which are easy to program using LabVIEW FPGA. LabVIEW FPGA abstracts all the complexity of programming in VHDL/Verilog and forces the user to best practices. You can check more details about FlexRIO boards at http://www.ni.com/flexrio/

While I have been using FPGAs for High Performance Computing, I was always interested in playing with FPGA's embedded applications. I started looking for some cheap boards so that I can start playing with them using VHDl so that I can understand the low-level FPGA details. Couple of boards I came across were:

1) Xess Board: Very Cheap and let's us get started easily.

Good Tutorials online about Xess:
http://www.xess.com/appnotes/FpgasNowWhatBook.pdf

Good Book on VHDL
http://www.freerangefactory.org/dl/free_range_vhdl.pdf

2) Digilent Board: Decent Price

I would strongly recommend checking out their videos at
http://www.youtube.com/user/LBEbooks



For the Step 1, I have used ATLYS from Digilent. Why Digilent ATLYS? My wife has this as part of her course work, so I wanted to put good use of some thing I already have available.

Components required for this programming practice:

1) ATLYS Board
2) Xilinx ISE for Synthesis and Simulation
3) Adept Software from Digilent (http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT)
4) Sigasi Editor Free Edition(Optional)
 Sigasi makes VHDL Programming easy and fun. Download it from http://www.sigasi.com/


Steps to create LED Blinker:

1) Download the VHDL code attached or create your own

https://github.com/kalyanramu/ATLYS

Important files in the repository to create bit files on your own
VHDL File Name: LEDBlink.vhd

Ready to use bit file:
Final Bit File: ledblink.bit

Most of the code was borrowed and idea was borrowed from
http://www.youtube.com/watch?v=2qx7Xef2LGE

2) Create the UCF File
Changes I have made are really in the UCF File.

Label L15 for the Clock was found from the manual. The board also shows GCLK <L15> label.
NET "CLK" LOC="L15";
NET "LED" LOC="U18";
NET "RST" LOC="A10";

Labels for LED LD0 ---> U18 and Switch SW0 ---> A10 can be found on the board

Note: Don't forget the semicolon at the end of line. Without ; the Xilinx compiler generates error.

3) Synthesize the Bit file
Watch the video tutorial in Step 1 for Synthesis

4) Power ON the board

After connecting the board to power outlet using power cable, flip the POWER switch beside the cable to ON. Verify that PGOOD and DONE LED's are ON.

5) Download/Program the Bitfile onto FPGA
I found that programming the FPGA using Adept Software easy. After installing the Adept Software, connect your board to PC.

Note: Connect the other end of USB cable from PC to USB Port on the board which is labeled as "PROG". If it is connected to other USB ports, proper driver won't be installed and the Adept software won't recognize the board

Adept GUI when ATLYS board is not detected



Adept GUI when ATLYS board is detected



You can download the VHDL Code from the links below: