Is it possible to create an alias variable/signal to improve readability of for
loops in VHDL processes?
For instance, consider the following module which contains a process with inner for
loops (code is for example purpose, I haven't test it):
library ieee;
use ieee.std_logic_1164.all;
entity MyModule is
port (
clk : in std_logic;
inData : in std_logic_vector(7 downto 0);
outData : out std_logic_vector(7 downto 0));
end MyModule;
architecture functional of MyModule is
type sample_vector is array (natural range <>) of std_logic_vector(9 downto 0);
type data_t is record
samples : sample_vector(3 downto 0);
-- other elements...
end record data_t;
type data_vector is array (natural range <>) of data_t;
signal data : data_vector(1 downto 0);
begin -- functional
process (clk)
begin -- process
if clk'event and clk = '1' then
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
data(d).samples(s)(9 downto 1) <= data(d).samples(s)(8 downto 0);
data(d).samples(s)(0) <= inData(d * 4 + s);
outData(d * 4 + s) <= '0';
for b in data(d).samples(s)'RANGE loop
if data(d).samples(s)(b) = '1' then
outData(d * 4 + s) <= '1';
end if;
end loop;
end loop;
end loop;
end if;
end process;
end functional;
Having to use data(d).samples(s)
every time I need to reference that signal is cumbersome, so I'd rather use an alias-like variable, something like that instead (inspired from generate
syntax, idx
part is just a bonus):
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
alias sample : std_logic_vector(9 downto 0) is data(d).samples(s);
constant idx : integer := d * 4 + s;
begin
sample(9 downto 1) <= sample(8 downto 0);
sample(0) <= inData(idx);
outData(idx) <= '0';
for b in sample'RANGE loop
if sample(b) = '1' then
outData(idx) <= '1';
end if;
end loop;
end loop;
end loop;
Of course, this does not work. So, is there any way to achieve something like that in VHDL, or do we always have to specify the full signal "path" each time?
I could replace the loop body with a procedure, but having to declare the procedure code in a (far away) different place of the file reduces readability even more. I could also use a for ... generate
construct, but this will create 1 process for each iteration and prevent me from using common process variables inside the iteration.
As indicated in question comments, this can be achieve using process variables:
process (clk)
variable sample : std_logic_vector(9 downto 0);
variable idx : integer;
begin -- process
if clk'event and clk = '1' then
-- Set outData(N) to '1' if at least 1 of the last 10 values of inData(N) was '1'
for d in data'RANGE loop
for s in data(0).samples'RANGE loop
-- Helpers
sample := data(d).samples(s);
idx := d * 4 + s;
outData(idx) <= '0';
for b in sample'RANGE loop
if sample(b) = '1' then
outData(idx) <= '1';
end if;
end loop;
sample(9 downto 1) <= sample(8 downto 0);
sample(0) <= inData(idx);
-- Do not forget to apply changes
data(d).samples(s) <= sample;
end loop;
end loop;
end if;
end process;
Of course, using process variables implies changing the operations order to get the same behavior.
Since process variables are read and written in the loops, I was worried the synthesis tools would believe the result of iteration N
was dependent on the result of iteration N-1
, and make implements the iterations in series (instead of in parallel). However, after unrolling the loop (which is what synthesis tools do), it gets clear the synthesis tools will see sample
and idx
values are not re-used between iterations.