VHDL coding tips and tricks: 2013

Saturday, August 17, 2013

How to write the current simulation time to a file in VHDL

In the past I have written few posts about file reading and writing in VHDL. In this post, we will address a specific issue related with testbench i.e writing the current simulation time in to a file. This kind of information is some times very useful for testing and debugging your design. 

This can be done using the textio package in vhdl. Let me show an example.

library ieee;
use STD.textio.all; 
use IEEE.STD_LOGIC_TEXTIO.all; 
 
entity rand_gen is
end rand_gen;
 
architecture behavior of rand_gen is 

begin

process
    variable L: line;
    variable T: time;
    variable line_var : line;
    file text_var : text;
begin    
    file_open(text_var,"time_file.txt",write_mode);  --open the file for writing.
    for i in 1 to 10 loop
        write(line_var, string'("The current simulation time is :"));
        write(line_var, time'IMAGE(now));
        writeline(text_var,line_var);
        wait for 10000 ns;
    end loop;
    file_close(text_var); 
    wait;
end process;

end behavior;

After the above code is run for sufficient time, a file named time_file.txt will be created with the following contents:

The current simulation time is :0 ps
The current simulation time is :10000000 ps
The current simulation time is :20000000 ps
The current simulation time is :30000000 ps
The current simulation time is :40000000 ps
The current simulation time is :50000000 ps
The current simulation time is :60000000 ps
The current simulation time is :70000000 ps
The current simulation time is :80000000 ps
The current simulation time is :90000000 ps


The code simply runs a for loop for 10 times, with a delay of 10000 ns between each write operation.

The predefined function now returns the current simulation time. time'image(X) returns a string representation of X that is of type time.  

The present simulation time is normally needed, when we need to know at what time exactly a certain event happens in vhdl. A well written testbench can make the testing process much more easier and fun. 

Note :- The code was tested using Xilinx ISE 13.1. But it should work with other simulation tools as well.

Thursday, August 15, 2013

Generating random numbers in a VHDL testbench

I have written two posts about random number generation in vhdl before. But these were written from a synthesisable point of view. So they are a bit complex. But if you are looking just for a simulatable code( for example to be used in a testbench) then there is a much simpler way to generate random numbers.

We use the procedure named UNIFORM which is defined in the IEEE library named math_real. Without too much explanation I will share the code with you.

library ieee;
use ieee.math_real.all;

entity rand_gen is
end rand_gen;

architecture behavior of rand_gen is 

signal rand_num : integer := 0;

begin

process
    variable seed1, seed2: positive;               -- seed values for random generator
    variable rand: real;   -- random real-number value in range 0 to 1.0  
    variable range_of_rand : real := 1000.0;    -- the range of random values created will be 0 to +1000.
begin
    uniform(seed1, seed2, rand);   -- generate random number
    rand_num <= integer(rand*range_of_rand);  -- rescale to 0..1000, convert integer part 
    wait for 10 ns;
end process;

end behavior;


The code generates random numbers with a time gap of 10 ns between two successive numbers. The variable named range_of_rand defines how big the random number can get. The uniform procedure generates numbers between 0.0 and 1.0. So to generate big numbers you just multiply it by a real number( in the above code 1000.0 ) and type cast it to an integer.

Using functions like conv_std_logic_vector or to_unsigned you can convert these random integers into binary format vectors. Remember to declare the required additional libraries in such cases.

Note :- The code was simulated using Xilinx ISE 13.1 Webpack. It should be able to work in other 

Sunday, August 4, 2013

BCD Addition - Behavioral level vhdl code

BCD or Binary coded decimal is a way of representing decimal digits in binary form. Generally 4 bits are used to represent values 0 to 9.

Decimal
Digit
BCD
8 4 2 1
00 0 0 0
10 0 0 1
20 0 1 0
30 0 1 1
40 1 0 0
50 1 0 1
60 1 1 0
70 1 1 1
81 0 0 0
91 0 0 1

In this post we discuss about BCD addition. The output of a BCD adder is also supposed to be in BCD format. So after the normal binary addition of the inputs, there should be a BCD adjustment code to convert the result to BCD format.

Consider the below BCD addition :

1001 + 1000 = 10001
   9 +    8 =    17

Since the range of input is 0 to 9, the maximum output is 18. If you consider a carry it becomes 19. This means at the output side we need a 4 bit sum and a 1 bit carry to represent the MSB digit.
For multiple digit addition , you can connect the carry_out to the carry input of the next adder. A simple cascading network of these small adders is enough to realize the multiple digit BCD addition.

VHDL code for single digit BCD addition:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bcd_adder is
    port(
        a,b  : in  unsigned(3 downto 0); -- input numbers.
        carry_in : in std_logic;
        sum  : out  unsigned(3 downto 0); 
        carry : out std_logic  
    );
end bcd_adder;

architecture arch of bcd_adder is


begin

process(a,b)
variable sum_temp : unsigned(4 downto 0);
begin
    sum_temp := ('0& a) + ('0& b) + ("0000" & carry_in); 
    if(sum_temp > 9) then
        carry <= '1';
        sum <= resize((sum_temp + "00110"),4);
    else
        carry <= '0';
        sum <= sum_temp(3 downto 0);
    end if; 
end process;   

end arch;

If you see the code, there are three inputs. The 4 bit BCD digits 'a' and 'b'. The carry_in comes from the carry output from the neighboring adder(in the LSB side). For the first adder(which adds the least significant digits) carry_in is '0'.

I have used the following test bench code to test the design. The code is synthesisable and have been tested using Xilinx ISE 13.1. It should work with other tools as well.

Testbench code for the BCD adder:-

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
 
ENTITY tb_test IS
END tb_test;
 
ARCHITECTURE behavior OF tb_test IS 

    COMPONENT bcd_adder
    PORT(
         a : IN  unsigned(3 downto 0);
         b : IN  unsigned(3 downto 0);
            carry_in : in std_logic;
         sum : OUT  unsigned(3 downto 0);
         carry : OUT  std_logic
        );
    END COMPONENT;
    
   signal a,b,sum : unsigned(3 downto 0) := (others => '0');
   signal carry,carry_in : std_logic;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: bcd_adder PORT MAP (
          a => a,
          b => b,
             carry_in => carry_in,
          sum => sum,
          carry => carry
        );
          
   -- Stimulus process
   stim_proc: process
   begin        
      a <= "1001"; b <= "1001"; carry_in <= '1'; wait for 100 ns;
        a <= "1000"; b <= "1001"; wait for 100 ns;
        a <= "0101"; b <= "1001"; wait for 100 ns;
        a <= "0011"; b <= "1001"; wait for 100 ns;
        a <= "1001"; b <= "0000"; carry_in <= '0'; wait for 100 ns;
        a <= "1001"; b <= "0111"; wait for 100 ns;
        a <= "0110"; b <= "0011"; wait for 100 ns;
      wait;
   end process;

END;

Note:- I have not given the code for cascading adders. But I hope its fairly simple to do it yourself.