Variables and signals in VHDL – and when variables are better

VHDL has two types of what-would-normally-be-called-variables:

  • signals, which must be used for inter-process communication, and can be used for process-local storage
  • variables which are local to a process.

(there’s also variables of a protected type which we’ll ignore for now as they’re another thing altogether)

Now one of the big differences between signals and variables is the way they are updated. When a signal is used within a process and is assigned to to change its value, the value does not update until the end of the process. For example (assume foo is “ to start with):

process
begin
  wait until rising_edge(clk);
  foo <= 1; -- an update is scheduled
  sig <= foo + 1; -- but hasn't happened yet, so sig is assigned 1 (again, only scheduled)
end process; -- at this point, foo is updated with the value 1 and sig also gets 1

Compare with the situation where foo is a variable:

process
  variable foo : integer;
begin
  wait until rising_edge(clk);
  foo := 1; -- foo gets 1 immediately
  sig <= foo + 1; -- so sig has an update to 2 scheduled
end process; -- at this point, foo is already 1 and sig gets its scheduled update to 2

This can cause some interesting effects on coding style – take for example this question on StackOverflow.

A code example is provided there which shows what has to happen due to the update semantics of signals – deeply nested ifs.

Here’s an alternative. Let’s define a procedure first of all to increment a variable and wrap around if it is greater than some maximum value. Also return a flag to inform us if the variable wrapped:

procedure inc_wrap (i : inout integer; maximum : positive; wrapped : inout boolean) is
begin
  if i = maximum then
    wrapped := true;
    i := 0;
  else
    wrapped := false;
    i := i + 1;
  end if;
end procedure;

Then our update process looks like this:

if second_enable = '1' then
  inc_wrap(s_ls_int, 9, wrapped);
  if wrapped then
    inc_wrap(s_ms_int, 5, wrapped);
  end if;
  if wrapped then
    inc_wrap(m_ls_int, 9, wrapped);
  end if;
  if wrapped then
    inc_wrap(m_ms_int, 5, wrapped);
  end if;
  if wrapped then
    if h_ms_int < 2 then -- wrap at 9 for 0-19 hour
      inc_wrap(h_ls_int, 9, wrapped);
    else -- wrap at 3 if past 20 hours
      inc_wrap(h_ls_int, 3, wrapped);
    end if;
  end if;
  if wrapped then
    inc_wrap(h_ms_int, 2, wrapped);
  end if;
end if;

All the code from this posting is at Github

Leave a comment

Your email address will not be published. Required fields are marked *