Reputation: 65
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
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
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
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