prerna B
prerna B

Reputation: 65

for-generate inside process vhdl

I know it is not possible to write for-generate inside the process but I want to achieve a functionality as presented by the code.It is basically an address decoder. Any help is appreciated.

The following code gives the syntax error : "Syntax error near generate"

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

entity address_decoder is
generic (CAM_DEPTH: integer := 8);
port (in_address: in std_logic_vector(CAM_DEPTH-1 downto 0);
        out_address: out std_logic_vector(2**CAM_DEPTH-1 downto 0);
        clk : in std_logic;
        rst: in std_logic
    );
end address_decoder;

architecture Behavioral of address_decoder is

begin
decode_process:
process(clk,rst) begin

if(clk'event and clk='1') then
        if (rst = '1') then
            out_address <= (others => '0');
        else
            NAME: for i in 0 to 10 generate
                if (i = to_integer(unsigned(in_address))) then
                    out_address(i) <= '1';
            else
                    out_address(i) <= '0';
                end if;
        end generate NAME;
end if;
end if;

end process;

 end Behavioral;

Upvotes: 4

Views: 28066

Answers (3)

Will Wang
Will Wang

Reputation: 113

Just like to add to previous answers,

GENERATE statement is concurrent statements, it can only be used in Architecture level.

PROCESS block can be sequential/concurrent, so I guess for this reason, GENERATE is not allowed inside a PROCESS block.

Upvotes: 1

Paebbels
Paebbels

Reputation: 16221

Your decoder is simply a binary to one-hot encoder with a downstream register. So you can extract the encoder and put it into a function

function bin2onehot(value : std_logic_vector) return std_logic_vector is
  variable result : std_logic_vector(2**value'length - 1 downto 0) := (others => '0');
begin
  result(2 ** to_integer(unsigned(value))) := '1';
  return result;
end function;

And this is your register:

process(clk)
begin
  if rising_edge(clk) then
    if (rst = '1') then
      out_address <= (others => '0');
    else
      out_address <= bin2onehot(in_address);
    end if;
  end if;
end process;

You can spare rst from the sensitivity list, because it's a synchronous reset.

Upvotes: 0

user1155120
user1155120

Reputation:

Use a loop statement:

decode_process:
    process(clk)   -- synchronous reset, no rst in sensitivity list
    begin

        if clk'event and clk = '1' then
            if rst = '1' then
                out_address <= (others => '0');
            else
                for i in 0 to 10 loop
                    if i = to_integer(unsigned(in_address)) then
                        out_address(i) <= '1';
                    else
                        out_address(i) <= '0' ;
                    end if;
                end loop;

                -- name: for i in 0 to 10 generate
                --     if (i = to_integer(unsigned(in_address))) then
                --         out_address(i) <= '1';
                --     else
                --         out_address(i) <= '0';
                --     end if;
                -- end generate name;
            end if;
        end if;
    end process;

Also notice rst was removed from the sensitivity list, it's written as a synchronous reset.

A loop statement can be synthesized, see now rescinded IEEE Std 1076.6-2004 8.8.9, Syntax, Sequential statements, Loop statement or your particular synthesis vendor's tool documentation. The sequential statements found in a loop are replicated for each value of the loop parameter which is treated as a constant.

So what's the difference between generate iteration and loop iteration?

Simulation cycles emulate concurrency for signal assignments even in sequential statements (e.g. in a process). There are no dependencies between one if statement and another in the synthesized (unrolled) loop. They will be i number of in_address recognizers comparing i to in_address each providing one bit of out_address. The first one assigning a(0), the second a(1)... In this case the loop statement will produce the same logic a generate statement would (using conditional signal assignment, although the sequential logic (clock) semantics would make it look awkward).

Let's compare this to using a generate statement in a concurrent statement appropriate place:

architecture foo of address_decoder is
    function to_std_ulogic (inp: boolean) return std_ulogic is
    begin
        if inp = TRUE then
            return '1';
        else
            return '0';
        end if;
    end;
begin

decoder:
    for i in 0 to 10 generate
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end generate;

end architecture;

The function to_std_ulogic taking a boolean argument has been added for brevity in the conditional signal assignment statement to out_address(i).

This looks nice and compact and may likely synthesize depending on the ability to use the function converting a boolean to a std_ulogic.

However, it expands out for elaboration:

architecture fum of address_decoder is
    function to_std_ulogic (inp: boolean) return std_ulogic is
    begin
        if inp = TRUE then
            return '1';
        else
            return '0';
        end if;
    end;
begin

decoder0: 
    block
        constant i: integer := 0;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder1: 
    block
        constant i: integer := 1;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder2: 
    block
        constant i: integer := 2;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder3: 
    block
        constant i: integer := 3;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder4: 
    block
        constant i: integer := 4;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder5: 
    block
        constant i: integer := 5;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder6: 
    block
        constant i: integer := 6;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder7: 
    block
        constant i: integer := 7;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder8: 
    block
        constant i: integer := 8;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder9: 
    block
        constant i: integer := 9;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
decoder10: 
    block
        constant i: integer := 10;
    begin
        out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)))
                          when clk'event and clk = '1';
    end block;
end architecture;

And worse still, each of those block statement concurrent conditional signal assignment statements become a process statement of the form:

decoder10:
    block
        constant i: integer := 10;
    begin
        process
        begin
            if clk'event and clk = '1' then
                out_address(i) <= to_std_ulogic(i = to_integer(unsigned(in_address)));
            end if;
        wait on clk, in_address;
        end process;

So now all the sudden instead of simulating one process you have eleven and each of those processes is sensitive to both clk and in_address, meaning the process with become active more than on just both clock edges.

So not only do the loop statement and the generate statement equivalent produce the same hardware after elaboration and synthesis, the loop statement is guaranteed to be faster in simulation, which is it's intended purpose.

Everything in a VHDL design specification devolves into block statements, process statements and subprograms (functions, procedures). Concurrent procedures are also devolved, while functions are expressions.

It's guaranteed that synthesis elaborates a design first. The synthesis difference in this case between the generate statement and a single process containing a loop is grouping. A process statement is translated separately unless a synthesis tool accepts an attribute allowing flattening (e.g. DISSOLVE_HIERARCHY as an attribute on the generate statement).

In the loop statement in a single process case you have the opportunity to share address recognizer logic between the 10 signal assignments by default, potentially generating less logic.

So there can be little difference in synthesis, but a significant difference in simulation, where the practical impact depends on the size of your design.

Upvotes: 15

Related Questions