The generate statement in VHDL can automatically duplicate a block of code to closures with identical signals, processes, and instances. It’s a for loop for the architecture region that can create chained processes or module instances.

Unlike a regular for loop, which can only exist in a process or a subprogram, the generate statement is placed directly in the architecture region of the VHDL file. When used together with generics, it becomes a powerful tool for designing customizable VHDL modules that allow for reuse across designs.

Generate statement syntax

The syntax of the generate statement is as follows:

[label :] for <constant_name> in <range> generate
  [declarations_local_to_each_loop_iteration]
[begin]
  <processes_and_instantiations>
end generate [label];

The parts enclosed in square brackets are optional. Thus, you may omit the declarative region and the begin keyword if you don’t want to declare any local objects. The <range> placeholder represents a standard integer range using to or downto.

One-bit switch debouncer

Before we start on the generate statement, I will present a simple module that we will use as an example throughout this article. It’s a debouncer capable of debouncing a single switch input.

To make it usable for any clock speed, I’ve added a generic input named timeout_cycles. This constant specifies how many clock cycles the timeout will be after the switch input changes. The debouncer will ignore any additional change in the switch value during the timeout period.

The listing below shows the entity of the debouncer module. There’s a bouncy switch input, and then there’s the clean switch_debounced output.

entity debouncer is
  generic (
    timeout_cycles : positive
    );
  port (
    clk : in std_logic;
    rst : in std_logic;
    switch : in std_logic;
    switch_debounced : out std_logic
  );
end debouncer;

The debouncer module relies on an integer counter to achieve the timeout period. The length of the counter signal follows the generic constant. That’s what the timeout duration specified during instantiation does.

Because we need to read the value of the switch_debounced output internally, I’ve declared a shadow signal named debounced, which we will use in its place. That’s a cleaner solution than the other option, which is to set inout mode on switch_debounce in the entity.

Finally, we implement the debouncing behavior in a single process, as shown in the code below.

architecture rtl of debouncer is

  signal debounced : std_logic;
  signal counter : integer range 0 to timeout_cycles - 1;

begin

  -- Copy internal signal to output
  switch_debounced <= debounced;

  DEBOUNCE_PROC : process(clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        counter <= 0;
        debounced <= switch;
        
      else
        
        if counter < timeout_cycles - 1 then
          counter <= counter + 1;
        elsif switch /= debounced then
          counter <= 0;
          debounced <= switch;
        end if;

      end if;
    end if;
  end process;

end architecture;

The waveform below shows a simulation of the debounce module in ModelSim. We can see that the switch_debounced output follows the switch input, but it ignores the immediate bouncing behavior after the first change — it debounces the signal.

Simulation waveform of the one-bit VHDL switch debouncer

Use the form below to download the VHDL code from this article. When you enter your email address, you will receive a Zip file containing the entire ModelSim project with testbenches and a quick-run script. You will receive future updates from VHDLwhiz, and you can unsubscribe at any time.

Need the ModelSim project files?

Let me send you a Zip with everything you need to get started in 30 seconds

How does it work?

Tested on Windows and Linux Loading Gif.. How it works

    Unsubscribe at any time

    Generate for loop with instantiations

    To make a debouncer for an array of switches, we’re going to use a generate statement to create multiple instances of our one-bit debouncer module.

    The listing below shows the entity of our new array or vector debouncer module. It’s similar to the one-bit debouncer, but there’s an additional generic input: switch_count. It specifies how many instances of the debouncer module to create. There should be one for each switch.

    Furthermore, I’ve renamed the switch input and output to the plural versions of the word, and they are now vectors instead of single bits.

    entity debouncer_gen_inst is
      generic (
        switch_count : positive;
        timeout_cycles : positive
        );
      port (
        clk : in std_logic;
        rst : in std_logic;
        switches : in std_logic_vector(switch_count - 1 downto 0);
        switches_debounced : out std_logic_vector(switch_count - 1 downto 0)
      );
    end debouncer_gen_inst;
    

    In the architecture, it’s time to use the generate statement. It works like a regular for loop, only with the word “generate” replacing the word “loop”. But unlike a regular for loop, it can contain module instantiations.

    The for loop runs at compile time and generates one instance of the debouncer module for each iteration. But because the “i” constant will be different for each iteration, we can use it to map the inputs and outputs of the debouncers to individual bits on the switches vectors, as shown below.

    architecture rtl of debouncer_gen_inst is
    begin
    
      MY_GEN : for i in 0 to switch_count - 1 generate
    
        DEBOUNCER : entity work.debouncer(rtl)
        generic map (
          timeout_cycles => timeout_cycles
        )
        port map (
          clk => clk,
          rst => rst,
          switch => switches(i),
          switch_debounced => switches_debounced(i)
        );
    
      end generate;
    
    end architecture;
    

    Note that it’s optional to label the generate statement, but it may be wise to do so. The label appears in the simulator hierarchy and the synthesis log, making it easier to identify the specific instance when debugging.

    The waveform below shows a simulation of the vector debouncer. We can see that the “MY_GEN” label reappears here, with indexes added for each of the eight debouncer instances.

    Waveform of 8-bit VHDL switch debouncer using generate for loop

    This testbench only changes the switch number 3 input, that’s what you see in the waveform and why I’ve expanded only the MY_GEN(3) group.

    You can quickly run this example on your computer if you have ModelSim installed. Use the form below to download the source code and the ModelSim project!

    Need the ModelSim project files?

    Let me send you a Zip with everything you need to get started in 30 seconds

    How does it work?

    Tested on Windows and Linux Loading Gif.. How it works

      Unsubscribe at any time

      Generate for loop containing processes

      In the last example of this article, we will be using a generate statement to make a series of identical processes. Instead of creating instances of the one-bit debouncer module, I’ve lifted the VHDL code from it. The entity is the same as in the previous example, and so is the behavior, but the implementation is different.

      We can see that I’ve moved the DEBOUNCE_PROC process within the generate statement and changed it slightly in the code below. This time I’m declaring two local signals within the generate statement: debounced and counter.

      Each iteration of the for loop will create an additional copy of the signals and the process. Using these signal names within the process will reference the ones scoped to the enclosure of that specific loop iteration.

      Finally, I’m assigning the debounced std_logic signal to the correct bit of the switches_debounced module output using a concurrent statement above the process.

      architecture rtl of debouncer_gen_proc is
      begin
      
        MY_GEN : for i in 0 to switch_count - 1 generate
      
          signal debounced : std_logic;
          signal counter : integer range 0 to timeout_cycles - 1;
      
        begin
      
          switches_debounced(i) <= debounced;
      
          DEBOUNCE_PROC : process(clk)
          begin
            if rising_edge(clk) then
              if rst = '1' then
                counter <= 0;
                debounced <= switches(i);
      
              else
      
                if counter < timeout_cycles - 1 then
                  counter <= counter + 1;
                elsif switches(i) /= debounced then
                  counter <= 0;
                  debounced <= switches(i);
                end if;
      
              end if;
            end if;
          end process;
      
        end generate;
      
      end architecture;
      

      I’ve omitted the simulation waveform because it looks precisely the same as in the previous example using module instantiation. The behavior is identical.

      You can download all the code using the form below. When you enter your email address, you subscribe to updates from VHDLwhiz. But don’t worry, there is an unsubscribe link in every email that I send.

      Need the ModelSim project files?

      Let me send you a Zip with everything you need to get started in 30 seconds

      How does it work?

      Tested on Windows and Linux Loading Gif.. How it works

        Unsubscribe at any time

        Leave a comment below if you have another useful application for generate statements to share! 😎

        Leave a Reply

        Your email address will not be published. Required fields are marked *

        This site uses Akismet to reduce spam. Learn how your comment data is processed.