Contact me for VHDL or Verilog projects and assignments

Tuesday, September 14, 2010

How to use "generate" keyword for multiple instantiation?

   Generate statement is a concurrent statement used in VHDL to describe repetitive structures.You can use generate statement in your design to instantiate multiple modules in two ways: the FOR-way and the IF-way.
   FOR-way is explained through a PISO(parallel in serial out) register example I have discussed earlier.The original post can be accessed here. I have modified the Gate level modeling code available in that post using "generate" statement.

--Library declaration.
library ieee;
use ieee.std_logic_1164.all;
--4 bit Parallel In Serial Out shift register(LSB is out first)
entity PISO is
port ( Serial_out : out std_logic;
       Parallel_In : in std_logic_vector(3 downto 0);
       --Load=1 means register is loaded parallely and Load=0 means right shift by one bit.
       Load : in std_logic;
       Clk : in std_logic
     );
end PISO;
architecture gate_level of PISO is
signal D,Q,Load_value : std_logic_vector(3 downto 0):="0000";
signal i : integer := 0;
begin
Load_value <= Parallel_In;
Serial_out <= Q(3);

--entity instantiation of the D flipflop using "generate".
F :  --label name
   for i in 0 to 3 generate   --D FF is instantiated 4 times.
    begin  --"begin" statement for "generate"
        FDRSE_inst : entity work.example_FDRSE port map   --usual port mapping
          (Q => Q(i),
          CLK => Clk,
          CE => '1',
          RESET => '0',
          D => D(i),
          SET => '0');
   end generate F;  --end "generate" block.
--The D inputs of the flip flops are controlled with the load input.
--Two AND gates with a OR gate is used for this.
D(0) <= Load_value(3) and Load;
D(1) <= (Load_value(2) and Load) or (Q(0) and not(Load));
D(2) <= (Load_value(1) and Load) or (Q(1) and not(Load));
D(3) <= (Load_value(0) and Load) or (Q(2) and not(Load));
end gate_level; 

I hope the above code is self explanatory.The for loop is used to instantiate as many number of modules as we want to instantiate.Next I will give an example on the IF-way using a Johnson counter example. The Johnson counter is explained with the help of VHDL code in one of my previous posts.Check it out here.I have modified the code using flip-flops available in this post.
The modified code is given below:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity johnson_counter is
port (
        DAT_O : out unsigned(3 downto 0);
        RST_I : in std_logic;
        CLK_I : in std_logic
        );
end johnson_counter;
architecture Behavioral of johnson_counter is
signal D,Q : unsigned(3 downto 0):="0000";
signal not_Q4 : std_logic:='0';
begin
not_Q4 <= not Q(3);
DAT_O <= Q;
F : for i in 0 to 3 generate
    begin
        F0 : if ( i = 0 ) generate  --The IF condition to for the "first" FF only.
            begin U1 : entity work.example_FDRSE port map --usual port mapping        
            (Q => Q(0),
          CLK => CLK_I,
          CE => '1',
          RESET => RST_I,
          D => not_Q4,
          SET => '0');
             end generate F0;
        F1 : if ( i /= 0 ) generate --generating the rest of the three FF's.
            begin U2 : entity work.example_FDRSE port map   --usual port mapping
         (Q => Q(i),
          CLK => CLK_I,
          CE => '1',
          RESET => RST_I,
          D => Q(i-1),
          SET => '0');
             end generate F1;
    end generate F;    
   
end Behavioral;


   So as you can see from the examples using "generate" keyword makes your design simple to understand  and saves your time.

Monday, September 13, 2010

Measure the time period/Frequency of an input Pulse

   This article is about how to find the time period of an input pulse using a simple counter and some adders.In some applications you may have a pulse input which has unknown or varying frequency.And you may need to find out this frequency.In this design I have two parts.
   First part is a counter which keeps on incrementing at the system clock frequency.When this counter reaches its maximum value it resets automatically and counts up again.The second part is triggered at every positive edge of the pulse input.So this part is triggered once every clock cycle of the pulse.In the second part we simply subtracts the last count from the current count to get the time period of the pulse in terms of the time period of the system clock.
For example if you see the simulation waveform I have attached at the bottom of this page you can see how this works:
1) pulse goes to '1' at 10 ns. Prev_Count is made "1000" which is the curr_count at 10 ns.
2) pulse goes to '0' at 110 ns. Nothing happens here. But all this time curr_count keeps on counting with the system clock.
3) pulse goes to '1' at 160 ns. Now we calculate (Curr_count - Prev_count ) = (16000 - 1000) =15000. This is how we get 15000 as the time period of the pulse input in terms of system clock. For getting the exact time period is ns you have to multiply the time period of system clock with the calculated value. Here we multiply 15000 with 10 ps = 150 ns.
4)For all this to work with good precision the frequency of the system clock should be very high compared to the frequency of pulse input. Otherwise the module will output the time period as "0" and a '1' will be asserted in the ERR_O output.
5)Whenever we calculate the time period of the pulse we update the prev_count with the current value of count.
6)Note that at time 1460.004 ns, at the new positive edge of pulse cycle we have a new time period calculated which is 130000 in relative terms or 1300 ns in absolute scale.
     The code for the design is given below:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity pulse_counter is
port ( DAT_O : out unsigned(47 downto 0);
         ERR_O : out std_logic;  --This is '1' if the pulse freq is more than clk freq.
         Pulse_I : in std_logic;  
       CLK_I : in std_logic
     );
end pulse_counter;
architecture Behavioral of pulse_counter is
signal Curr_Count,Prev_Count : unsigned(47 downto 0):=(others => '0');
begin
--Increment Curr_Count every clock cycle.This is the max freq which can be measured by the module.
process(CLK_I)
begin
    if( rising_edge(CLK_I) ) then
        Curr_Count <= Curr_Count + 1;
    end if;
end process;
--Calculate the time period of the pulse input using the current and previous counts.
process(Pulse_I)
begin
    if( rising_edge(Pulse_I) ) then
    --These different conditions eliminate the count overflow problem
    --which can happen once the module is run for a long time.
       if( Prev_Count < Curr_Count ) then
            DAT_O <= Curr_Count - Prev_Count;
            ERR_O <= '0';
        elsif( Prev_Count > Curr_Count ) then
        --X"F_F" is same as "1111_1111".
        --'_' is added for readability.
            DAT_O <= X"1_0000_0000_0000" - Prev_Count + Curr_Count;    
            ERR_O <= '0';
        else
         DAT_O <= (others => '0');
            ERR_O <= '1';  --Error bit is inserted here.
        end if;    
        Prev_Count <= Curr_Count;  --Re-setting the Prev_Count.
    end if;
end process;
end Behavioral;

The testbench code used for testing the design is given below:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY tb IS
END tb;
ARCHITECTURE behavior OF tb IS
   --Inputs
   signal Pulse_I : std_logic := '0';
   signal CLK_I : std_logic := '0';
    --Outputs
   signal DAT_O : unsigned(47 downto 0);
   signal ERR_O : std_logic;
   -- Clock period definitions
   constant CLK_I_period : time := 10 ps;
BEGIN
    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.pulse_counter PORT MAP (
          DAT_O => DAT_O,
          ERR_O => ERR_O,
          Pulse_I => Pulse_I,
          CLK_I => CLK_I
        );
   -- Clock process definitions
   CLK_I_process :process
   begin
        CLK_I <= '0';
        wait for CLK_I_period/2;
        CLK_I <= '1';
        wait for CLK_I_period/2;
   end process;
   -- Stimulus process
   stim_proc: process
   begin       
      wait for 10 ns;
        --1  (time period is 15000*10 ps here)
        Pulse_I <= '1';
        wait for 100 ns;
        Pulse_I <= '0';
        wait for 50 ns;
        Pulse_I <= '1';
        --2  (Error because freq of pulse is less than system clock)
        wait for 3 ps;
        Pulse_I <= '0';
        wait for 1 ps;
        Pulse_I <= '1';
        --3  (time period is 130000*10 ps here)
        wait for 300 ns;
        Pulse_I <= '0';
        wait for 1000 ns;
        Pulse_I <= '1';    
      wait;
   end process;
END;

The simulation wave form is shown below:
  Markers are added in the waveform for clearly understanding the positive edges of the pulse wave.Go through the wave form along with the codes and the explanation given above.

Example : 4 bit Johnson Counter with testbench

    A Johnson counter is a digital circuit which consists of a series of flip flops connected together in a feedback manner.The circuit is special type of shift register where the complement output of the last flipflop is fed back to the input of first flipflop.This is almost similar to ring counter with a few extra advantages.When the circuit is reset all the flipflop outputs are made zero. For n-flipflop Johnson counter we have a MOD-2n counter. That means the counter has 2n different states.
The circuit diagram for a 3 bit Johnson counter is shown below:
 The VHDL code for 4 bit Johnson counter is shown below:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity johnson_counter is
port (
        DAT_O : out unsigned(3 downto 0);
        RST_I : in std_logic;
        CLK_I : in std_logic
        );
end johnson_counter;

architecture Behavioral of johnson_counter is

signal temp : unsigned(3 downto 0):=(others => '0');

begin

DAT_O <= temp;

process(CLK_I)
begin
    if( rising_edge(CLK_I) ) then
        if (RST_I = '1') then
            temp <= (others => '0');
        else
            temp(1) <= temp(0);
            temp(2) <= temp(1);
            temp(3) <= temp(2);
            temp(0) <= not temp(3);
        end if;
    end if;
end process;
   
end Behavioral;

The testbench code used for testing the design is given below:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb2 IS
END tb2;

ARCHITECTURE behavior OF tb2 IS
   --Inputs
   signal RST_I : std_logic := '0';
   signal CLK_I : std_logic := '0';
    --Outputs
   signal DAT_O : unsigned(3 downto 0);
   -- Clock period definitions
   constant CLK_I_period : time := 1 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.johnson_counter PORT MAP (
          DAT_O => DAT_O,
          RST_I => RST_I,
          CLK_I => CLK_I
        );

   -- Clock process definitions
   CLK_I_process :process
   begin
        CLK_I <= '0';
        wait for CLK_I_period/2;
        CLK_I <= '1';
        wait for CLK_I_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin       
        RST_I <= '1';
      wait for 2 ns;   
        RST_I <= '0';
        wait for 2 ns; 
        RST_I <= '1';
        wait for 1 ns; 
        RST_I <= '0';
      wait;
   end process;

END;

The simulation waveform is given below:

Example : 4 bit Ring Counter with testbench

   A ring counter is a digital circuit which consists of a series of flip flops connected together in a feedback manner.The circuit is special type of shift register where the output of the last flipflop is fed back to the input of first flipflop.When the circuit is reset, except one of the flipflop output,all others are made zero. For n-flipflop ring counter we have a MOD-n counter. That means the counter has n different states.
The circuit diagram for a 4 bit ring counter is shown below:

   I have written a VHDL code for a 4-bit ring counter which has the following states:
0001  -   0010   -  0100   -   1000 ....
The code is posted below:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ring_counter is
port (
        DAT_O : out unsigned(3 downto 0);
        RST_I : in std_logic;
        CLK_I : in std_logic
        );
end ring_counter;

architecture Behavioral of ring_counter is

signal temp : unsigned(3 downto 0):=(others => '0');

begin

DAT_O <= temp;

process(CLK_I)
begin
    if( rising_edge(CLK_I) ) then
        if (RST_I = '1') then
            temp <= (0=> '1', others => '0');
        else
            temp(1) <= temp(0);
            temp(2) <= temp(1);
            temp(3) <= temp(2);
            temp(0) <= temp(3);
        end if;
    end if;
end process;
   
end Behavioral;

The testbench code used for testing the design is given below:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS
   --Inputs
   signal RST_I : std_logic := '0';
   signal CLK_I : std_logic := '0';
    --Outputs
   signal DAT_O : unsigned(3 downto 0);
   -- Clock period definitions
   constant CLK_I_period : time := 1 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.ring_counter PORT MAP (
          DAT_O => DAT_O,
          RST_I => RST_I,
          CLK_I => CLK_I
        );

   -- Clock process definitions
   CLK_I_process :process
   begin
        CLK_I <= '1';
        wait for CLK_I_period/2;
        CLK_I <= '0';
        wait for CLK_I_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin       
        RST_I <= '1';
      wait for 2 ns;   
        RST_I <= '0';
        wait for 5 ns; 
        RST_I <= '1';
        wait for 1 ns; 
        RST_I <= '0';
      wait;
   end process;

END;

The simulation wave form is given below:

Thursday, September 9, 2010

Examples for Gate Level and Behavior Level Designs

   This article is about the two major type of modeling available in VHDL - Gate Level and Behavior level.
In gate level modeling the module is implemented in terms of logic gates and interconnections between these gates.Design at this level is similar to describing a circuit in terms of a gate level logic diagram.
In Behavior level(Algorithmic level) modeling a module is implemented in terms of the desired design algorithm without the concern for the hardware circuit elements.Designing at this level is the highest abstraction level provided by VHDL.
  For understanding the difference between the two models I have designed a PISO(Parallel In Serial Out) in both the models. See the behavioral level code below:

--Library declaration.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity piso is
    PORT(
         Serial_out : OUT  std_logic;
         Parallel_In : IN  std_logic_vector(3 downto 0);
         Load : IN  std_logic;
         Clk : IN  std_logic
        );
end piso;
architecture Behavioral of piso is
signal Load_value : std_logic_vector(3 downto 0):="0000";
begin
process(Clk)
begin
    if(rising_edge(Clk)) then
        if( Load ='0' ) then  --Do the serial right shifting here.
            Serial_Out <= Load_value(3);
            Load_value(3) <= Load_value(2);
            Load_value(2) <= Load_value(1);
            Load_value(1) <= Load_value(0);
            Load_value(0) <= '0';
      else   --Load the registers with a new value to shift.
            Load_value <= Parallel_In;
        end if;
    end if;
end process;
end Behavioral;

  If you check the code above then you can see that the code is written using some if..else.. statements. We havent used any digital circuit elements like flip-flops,gates,registers etc. The code describes the working in a language similar to a high level language like C (but there are lot of difference between C and VHDL, and they are not even comparable).
Now let us check the Gate level code:

--Library declaration.
library ieee;
use ieee.std_logic_1164.all;
--4 bit Parallel In Serial Out shift register(LSB is out first)
entity PISO is
port ( Serial_out : out std_logic;
         Parallel_In : in std_logic_vector(3 downto 0);
         --Load=1 means register is loaded parallely and Load=0 means right shift by one bit.
         Load : in std_logic;  
       Clk : in std_logic
     );
end PISO;
architecture gate_level of PISO is
signal D1,D2,D3,D4,Q1,Q2,Q3,Q4 : std_logic :='0';
signal Load_value : std_logic_vector(3 downto 0):="0000";
begin
Load_value <= Parallel_In;
Serial_out <= Q4;
--entity instantiation of the D flipflop.It is instantiated 4 times to make 4 bit register.
FDRSE1 : entity work.example_FDRSE  --MSB
 port map (
      Q => Q1,  
      CLK => Clk,
      CE => '1',
      RESET => '0',
      D => D1,
      SET => '0'
   );
FDRSE2 : entity work.example_FDRSE
 port map (
      Q => Q2,  
      CLK => Clk,
      CE => '1',
      RESET => '0',
      D => D2,
      SET => '0'
   );  
FDRSE3 : entity work.example_FDRSE
 port map (
      Q => Q3,  
      CLK => Clk,
      CE => '1',
      RESET => '0',
      D => D3,
      SET => '0'
   );
FDRSE4 : entity work.example_FDRSE  --LSB
 port map (
      Q => Q4,  
      CLK => Clk,
      CE => '1',
      RESET => '0',
      D => D4,
      SET => '0'
   );
--The D inputs of the flip flops are controlled with the load input.
--Two AND gates with a OR gate is used for this.
D1 <= Load_value(3) and Load;
D2 <= (Load_value(2) and Load) or (Q1 and not(Load));
D3 <= (Load_value(1) and Load) or (Q2 and not(Load));
D4 <= (Load_value(0) and Load) or (Q3 and not(Load));
end gate_level;

 In the above code you can notice the following features of Gate level code:
1)We have used VHDL gate level primitives like not,and,or etc in the program.
2)The flip flop required for implementing the 4 bit register was instantiated separately. The flip flop code was taken from one of my earlier post and it is another example of behavior level modeling.Check the flip flop code here.
3)We havent used a "process" statement in the program.
4)The above code is also an example of Structural level modeling where we use a hierarchy of modules.For example the D flip flop is considered as a black box from the PISO module's point of view.Once the flip flop (or generally any other module) is designed and verified we can use it any number of times any where in a bigger design.This type of design is called structural level design. Some more examples can be found here : 4 bit synchronous UP counter.
5)You can find more example codes for gate level modeling here : 3 to 8 decoder using basic logic gates and 4 bit ripple carry adder.
I have written the following testbench code for verifying my design.You can edit and check for more input combination for learning purpose.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY tb IS
END tb;
ARCHITECTURE behavior OF tb IS
   --Inputs
   signal Parallel_In : std_logic_vector(3 downto 0) := (others => '0');
   signal Load : std_logic := '0';
   signal Clk : std_logic := '0';
    --Outputs
   signal Serial_out : std_logic;
   -- Clock period definitions
   constant Clk_period : time := 10 ns;
BEGIN
    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.PISO PORT MAP (
          Serial_out => Serial_out,
          Parallel_In => Parallel_In,
          Load => Load,
          Clk => Clk
        );
   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;
   -- Stimulus process
   stim_proc: process
   begin   
   wait for 25 ns; 
   load <= '1';
    parallel_in <= "1011";
    wait for 10 ns;
    load<='0';
   
   wait for 60 ns; 
   load <= '1';
    parallel_in <= "1101";
    wait for 10 ns;
    load<='0';
      wait;
   end process;
END;

The simulation result is shown below:

Note:- I have instantiated modules using the "entity instantiation" method. If you are new to this method please read this article.

Wednesday, September 8, 2010

Example : D Flip-Flop with Asynchronous Clear,Set and Clock Enable

    As per the request from readers I have decided to post some basic VHDL codes for beginners in VHDL. This is the second one in the series, a basic D Flip-Flop with Asynchronous Clear,Set and Clock Enable(negedge clock).The code is self explanatory and I have added few comments for easy understanding.


--library declaration for the module.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--This is a D Flip-Flop with Asynchronous Clear,Set and Clock Enable(negedge clock).
--Note that the clear input has the highest priority,preset being the next highest
--priority and clock enable having the lowest priority
entity example_FDCPE is
   port(
      Q : out std_logic;      -- Data output
      CLK :in std_logic;      -- Clock input
      CE :in std_logic;    -- Clock enable input
      CLR :in std_logic;  -- Asynchronous clear input
      D :in  std_logic;      -- Data input
      PRE : in std_logic   -- Asynchronous set input
   );
end example_FDCPE;

architecture Behavioral of example_FDCPE is  --architecture of the circuit.

begin  --"begin" statement for architecture.

process(CLR,PRE,CLK) --process with sensitivity list.
begin  --"begin" statment for the process.

    if (CLR = '1') then  --Asynchronous clear input
           Q <= '0';
    else
           if(PRE = '1') then  --Asynchronous set input
               Q <= '1';
           else
               if ( CE = '1' and  falling_edge(CLK) ) then
                  Q <= D;      
              end if;
          end if;
   end if;

end process;  --end of process statement.

end Behavioral;

Note :- This is a flip flop which is defined in the Xilinx language template for spartan-3.If you synthesis this design it will use exactly one flip flop and some buffers alone.It will not use any LUT's for the implementation.

Example : D Flip-Flop with Synchronous Reset,Set and Clock Enable

   As per the request from readers I have decided to post some basic VHDL codes for beginners in VHDL. This is the first one, a basic D Flip-Flop with Synchronous Reset,Set and Clock Enable(posedge clock).The code is self explanatory and I have added few comments for easy understanding.
--library declaration for the module.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--This is a D Flip-Flop with Synchronous Reset,Set and Clock Enable(posedge clk).
--Note that the reset input has the highest priority,Set being the next highest
--priority and clock enable having the lowest priority.
entity example_FDRSE is
   port(
      Q : out std_logic;      -- Data output
      CLK :in std_logic;      -- Clock input
      CE :in std_logic;    -- Clock enable input
      RESET :in std_logic;  -- Synchronous reset input
      D :in  std_logic;      -- Data input
      SET : in std_logic   -- Synchronous set input
   );
end example_FDRSE;
architecture Behavioral of example_FDRSE is  --architecture of the circuit.
begin  --"begin" statement for architecture.
process(CLK) --process with sensitivity list.
begin  --"begin" statment for the process.
  if ( rising_edge(CLK) ) then  --This makes the process synchronous(with clock)
    if (RESET = '1') then
         Q <= '0';
     else
           if(SET = '1') then
             Q <= '1';
           else
              if ( CE = '1') then
               Q <= D;      
             end if;
           end if;
      end if;
  end if;      
end process;  --end of process statement.
end Behavioral;
Note :- This is a flip flop which is defined in the Xilinx language template for spartan-3.If you synthesis this design it will use exactly one flip flop and some buffers alone.It will not use any LUT's for the implementation.
Related Posts with Thumbnails