𝐐𝐮𝐞𝐬𝐭𝐢𝐨𝐧: VHDL allows utilization of variable types inside process, function or procedure. They are different than signals in many ways, but most important one is variables are assigned immediately unlike signals. The question is, how many FFs infer for a variable in a clocked process?

𝐀𝐧𝐬𝐰𝐞𝐫: The most common usage of variables is as follows:

  • First assign values to variables; i.e. initialize them
  • Then write your algorithm utilizing variables by reading or writing them
  • Finally, assign variables to the signals

There is a simple rule for FF inference of variables inside a clocked process: If a variable is read before assigned in the sequence inside a process, then it infers register. So, if you follow the common approach, variables will not infer registers but only signals will.

Let’s see the synthesis result with an example of parity calculation of a bit vector:

library IEEE;
use IEEE.std_logic_1164.all;

entity VARTEST is 
port (
clk         : in std_logic;
input1      : in std_logic_vector (7 downto 0);
output1     : out std_logic
);
end VARTEST;

architecture RTL of VARTEST is 

begin 


process (clk)
    variable TMP : std_logic;
begin 
if (rising_edge(clk)) then

    TMP := '0';
    for J in input1'range loop 
        TMP := TMP xor input1(J);
    end loop;
    output1 <= TMP;

end if;
end process;

end RTL;

Here is the netlist schematics of the Vivado for the code below:

FPGA & VHDL KnowHow Series - 9 - 1

We can also use a function to utilize variables and evaluate the synthesis result:

library IEEE;
use IEEE.std_logic_1164.all;

entity VARTEST is 
port (
clk         : in std_logic;
input1      : in std_logic_vector (7 downto 0);
output1     : out std_logic
);
end VARTEST;

architecture RTL of VARTEST is 

function PARITY_FUNC (FP : std_logic_vector)
                        return std_logic is 
    variable TMP : std_logic;
begin 
    TMP := '0';
    for J in FP'range loop 
        TMP := TMP xor FP(J);
    end loop;
    return TMP;
end PARITY_FUNC;

begin 

process (clk) begin 
if (rising_edge(clk)) then

    output1 <= PARITY_FUNC(input1);

end if;
end process;

end RTL;

The netlist schematics also shows that only 1 FF is inferred.

FPGA & VHDL KnowHow Series - 9 - 2

Let’s see what’s going to happen if we first read a variable inside a process and then use it. Here is an example code, where 3 variables are read before assignment and 3 variables are assigned first and then read. Finally, a signal is assigned to a function of the all variables.

library IEEE;
use IEEE.std_logic_1164.all;

entity VARTEST is 
port (
clk         : in std_logic;
input1      : in std_logic_vector (2 downto 0);
output1     : out std_logic_vector (2 downto 0)
);
end VARTEST;

architecture RTL of VARTEST is 

begin 

process (clk)
    variable TMP1 : std_logic;
    variable TMP2 : std_logic;
    variable TMP3 : std_logic;
    variable TMP4 : std_logic;
    variable TMP5 : std_logic;
    variable TMP6 : std_logic;
begin 
if (rising_edge(clk)) then
    TMP1 := input1(0);
    TMP2 := input1(1);
    TMP3 := input1(2);
    output1(0) <= TMP4 or TMP1;
    output1(1) <= TMP5 or TMP2;
    output1(2) <= TMP6 or TMP3;
    TMP4 := TMP1;
    TMP5 := TMP2;
    TMP6 := TMP3;
end if;
end process;

end RTL;

Here is the netlist schematics result of the Vivado for the code below:

FPGA & VHDL KnowHow Series - 9 - 3

We see 3 FFs are inferred for output1, which is expected. We also see 3 more FFs are inferred for TMP4, TMP5 and TMP6 due to the fact that they are first read before assignment inside the process.

To summarize, do not forget this simple rule while using variables in VHDL, if a variable is read before assigned in the sequence inside a process, then it infers register. If you know what you are doing, then it is OK, but the common usage of variables is first you initialize them and then use them. Finally assign variables to signals.

“𝑺𝒉𝒂𝒓𝒊𝒏𝒈 𝒌𝒏𝒐𝒘𝒍𝒆𝒅𝒈𝒆 𝒊𝒔 𝒕𝒉𝒆 𝒎𝒐𝒔𝒕 𝒆𝒇𝒇𝒊𝒄𝒊𝒆𝒏𝒕 𝒍𝒆𝒂𝒓𝒏𝒊𝒏𝒈 𝒎𝒆𝒕𝒉𝒐𝒅”