VHDL: A synthesizable delay generator instead of 'wait for' statement

 CODE UPDATED ON 01/11/2017 AFTER IMPROVISING!

THE ARTICLE WAS UPDATED AGAIN ON 04/03/2024!

There are many situations in which you may need to activate a process after a certain delay or at fixed time intervals.If you want to do simulation alone for your design then you can simply use "wait for" statement to call a delay routine.But this keyword is not synthesizable. So what will you do in such situations?

A simple delay routine,which is synthesizable, can be designed using the properties of a "MOD-n counter". A MOD-n counter can be used to generate a frequency of (f / n) using a frequency 'f'. The code for generating such a delay is given below:

VHDL Design:

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

entity delay_gen is
  port (clk,reset : in std_logic; 
        delay_cycles : in unsigned(31 downto 0);   --delay to be generated.
        flag : out std_logic --this is a pulse to notify that time interval equal to delay is over.
    );
end delay_gen;

architecture Behavioral of delay_gen is

signal count : unsigned(31 downto 0) := (others => '0');

begin

process(clk,reset)
begin
    if(reset = '1') then
        flag <= '0';
        count <= (others => '0');
    elsif(rising_edge(clk)) then
    --when the necessary delay is achieved, reset count and set flag high
        if(count = delay_cycles-1) then 
            count <= (others => '0');
            flag <= '1';
        else
            flag <= '0';
            count <= count +1;   --increment counter otherwise.
        end if; 
    end if;

    
end process;

end Behavioral;

The module has 3 inputs including a clock and a reset signal. The delay_cycles input determines the amount of delay generated by the code.

We can write,

delay_cycles = [Delay in seconds] / [Clock period of clk].

Suppose you want a delay of 100 ns. Let's say your clk frequency is 100 MHz. That  means your clock period is 10 ns. So the value of delay_cycles should be equal to (100 ns / 10 ns) = 10. When the counter counts from 0 to 9, it outputs a pulse on the flag output port.

Few more example values of delay_cycles are given below for different delay times. Lets assume that system clock frequency is 100 MHz.

How many counts for delay statement

The following testbench code demonstrates how this can be done in practice. 

Testbench Code:

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

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS 

    -- Component Declaration for the Unit Under Test (UUT) 
    COMPONENT delay_gen
     port (clk,reset : in std_logic; 
        delay_cycles : in unsigned(31 downto 0);   --delay to be generated.
        flag : out std_logic --this is a pulse to notify that time interval equal to delay is over.
    );
    END COMPONENT;
    

   --Inputs
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
   signal delay_cycles : unsigned(31 downto 0) := (others => '0');
    --Outputs
   signal flag : std_logic;

   -- Clock period definitions
   constant clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: delay_gen PORT MAP (
          clk => clk,
          reset => reset,
          delay_cycles => delay_cycles,
          flag => flag
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '1';
        wait for clk_period/2;
        clk <= '0';
        wait for clk_period/2;
   end process;


   -- Stimulus process
   stim_proc: process
   begin        
      reset <= '1';
        wait for clk_period*10;
        reset <= '0';
        --by setting the input as "10", I want a delay of 10 clock cycles.
        --in real time,the delay = 10*period of clock.
        --so here in simulation, delay = 10*10 ns = 100 ns.
        delay_cycles <= to_unsigned(10,32);
      wait;
   end process;

END;

Simulation Waveform:




This code can be used in many situations, for example:
  1. To run some parts of your design at a lesser clock frequency than your system clock.
  2. To create a delay between some of the processes.
  3. To create a 'wait for X seconds' function. 
The range of delay values can be increased by increasing the size of delay_cycles. Note that the maximum error in the delay produced is equal to the period of input clock.

Post a Comment

4 Comments

  1. Thanks for the code,

    Can I have the same in verilog?

    ReplyDelete
  2. @kartik : yeah. You can use the basic idea here to write a similar code in verilog.

    ReplyDelete
  3. but how do i use this in a desgin code? for example if i want to implement a flip flop how do i encode this mod-n counter in the code for flip flop...can u please give an example? I'm a novice.

    ReplyDelete
  4. @nebula : any MOD-n counter can be designed using flip flops.You just have to reset all the flip flops when the output reaches the particular count.If it is 3 bit counter , and you want the max count to be "5" then the reset input of all FF's should be connected to R= count(0) xor (not count(1)) xor count(2).

    ReplyDelete