The real issue here is that signals can be used throughout a design and are usually registered, while variables can only be used within a VHDL process and take on immediate values. Often a variable is used to trigger another condition or state immediately within a process rather than waiting for the signal to be asserted on the next clock edge.
Consider the case of a counter, declared with a record type, and used as a variable and then assigned as a signal (registered):
/*-------------------------------------------
Count the number of samples
---------------------------------------------*/
counter.start <= START;
process(all)
variable counterVal : integer range 0 to Nsamples;
begin
if HRST then
counterVal := 0;
counter.val <= (others => '0');
counter.done <= '0';
elsif rising_edge(MCLK) then
if load then
counterVal := Nsamples-1;
counter.done <= '0';
elsif counter.start then
if counter.val > 0 then
counterVal := counterVal - 1;
counter.done <= '0';
else
counter.done <= '1';
end if;
end if;
counter.val <= std_logic_vector(to_unsigned(counterVal,16));
end if;
end process;
where the record type is declared as:
type counterType is record
start : std_logic;
done : std_logic;
val : integer range 0 to Nsamples-1;
end record;
signal counter : counterType;
Conversely, consider the case of the same counter with signal type only.
/*-------------------------------------------
Count the number of samples
---------------------------------------------*/
counter.start <= START;
process(all) begin
if HRST then
counter.val <= 0;
counter.done <= '0';
elsif rising_edge(MCLK) then
if load then
counter.val <= Nsamples-1;
counter.done <= '0';
elsif counter.start then
if counter.val > 0 then
counter.val <= counter.val - 1;
counter.done <= '0';
else
counter.done <= '1';
end if;
end if;
end if;
end process;